Redis的有序集合(Sorted Set)是日常开发中使用频率很高的数据结构,它既能像集合一样去重,又能为每个成员维护一个分数字值,天然适合排行榜、延时队列、热度统计这类场景。但很多时候我们需要的不只是单个有序集合的数据,而是多个集合之间的运算结果,比如两个榜单的共同上榜用户、同时打了多个标签的商品。Redis提供了ZINTERSTORE命令,专门用于计算多个有序集合的交集并把结果存储到一个新的键中,整个计算过程在服务端完成,避免了把数据拉到客户端再做处理的性能开销。

ZINTERSTORE命令的基本语法与参数详解
ZINTERSTORE的完整语法形式是ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]。其中destination是存储计算结果的目标键,numkeys指定参与运算的源集合数量,后面跟上具体的key列表。命令执行成功后返回值是结果集合中成员的数量,同时目标键中原有的数据会被完全覆盖。
WEIGHTS参数的作用是为每个源集合指定一个乘法系数,在聚合之前每个集合中成员的分数会先乘以对应的权重。比如设置WEIGHTS 2 3,表示第一个集合的分数乘以2,第二个集合的分数乘以3。权重的默认值是1,权重数量必须与numkeys一致,否则Redis会直接报错。
AGGREGATE参数决定了多个集合中同一成员的分数如何合并,可选值有SUM、MIN和MAX三种。SUM是默认行为,即把各集合中的分数相加;MIN取所有分数中的最小值;MAX则取最大值。下面通过一个简单的例子演示基本用法:
# 准备两个有序集合 ZADD math_score 85 "zhangsan" 92 "lisi" 78 "wangwu" ZADD english_score 90 "zhangsan" 80 "lisi" 95 "zhaoliu" # 计算交集,分数求和 ZINTERSTORE total_score 2 math_score english_score # 结果:zhangsan=175, lisi=172, wangwu和zhaoliu被排除 # 查看结果 ZRANGE total_score 0 -1 WITHSCORES
可以看到,只有同时出现在两个集合中的成员才会进入结果集,这正是一般交集运算的定义。单科成绩表里的wangwu和zhaoliu因为没有同时参加两门考试,所以不会出现在总分榜中。
WEIGHTS与AGGREGATE的组合实战
单纯求和在很多业务场景下并不合理。以加权总分为例,假设期末评定中数学占60%、英语占40%,就可以利用WEIGHTS参数实现,权重可以用小数表示:
# 数学权重0.6,英语权重0.4 ZINTERSTORE weighted_score 2 math_score english_score WEIGHTS 0.6 0.4 AGGREGATE SUM # zhangsan: 85*0.6 + 90*0.4 = 87 # lisi: 92*0.6 + 80*0.4 = 87.2 ZRANGE weighted_score 0 -1 WITHSCORES WITHSCORES
AGGREGATE MIN则适合求均衡型指标的场景。比如挑选各科目都不偏科的学生,用MIN聚合就能得到每个学生在其最弱科目上的分数,结果天然按短板能力排序。反过来说,如果要用ZINTERSTORE实现这种短板筛选,配合ZRANGE取降序前几名即可完成。
还有一个容易被忽略的细节:目标键destination如果原本存在,无论它是字符串、列表还是其他类型,ZINTERSTORE都会直接覆盖它,且这种覆盖不会触发过期时间的继承。结果键默认是持久化的,如果希望它临时存在,需要在命令执行后再单独调用EXPIRE设置过期时间。
ZINTERSTORE与ZUNIONSTORE及相关命令的对比
Redis中与ZINTERSTORE关系最密切的是ZUNIONSTORE,两者的参数格式完全一致,区别只在于一个取交集、一个取并集。并集运算会保留所有源集合中的成员,聚合方式同样支持SUM、MIN、MAX。实际选型时要看业务语义:找共同成员用INTER,做全量合并用UNION。
另外需要注意,参与运算的key如果不是有序集合而是普通集合(SET),Redis也允许这样做,此时普通集合中的成员分数会被当作1来处理。这个特性在做标签筛选时非常实用,可以把标签集合当作过滤器与业务分数集合做交集:
# 活跃用户集合(普通SET) SADD active_users "zhangsan" "lisi" "wangwu" # 会员积分有序集合 ZADD member_points 500 "zhangsan" 320 "lisi" 800 "tianqi" # 筛选出既活跃又有积分记录的用户 ZINTERSTORE active_members 2 active_users member_points ZRANGE active_members 0 -1 WITHSCORES # 结果只有zhangsan(500)和lisi(320)
如果只是想查看交集结果而不需要存储,Redis 6.2之后提供了ZINTER命令,它不写入目标键,直接返回交集成员,避免了产生临时键的额外内存占用,适合一次性的查询场景。在旧版本中也可以用ZINTERSTORE写入临时键再删除的方式模拟,但要注意原子性和清理时机。
性能考量与使用注意事项
ZINTERSTORE的计算复杂度是O(N*log(N)),其中N是所有输入集合基数的最小值乘以输出结果数。当参与运算的集合非常大时,这个命令可能成为性能瓶颈,因为Redis是单线程处理命令的,耗时的集合运算会阻塞其他请求。生产环境中如果集合规模达到百万级别,建议在从库执行或者错峰运行。
结果键的数据量也需要关注。交集运算的结果可能很大,如果destination键长期存在且不断被覆盖重建,会造成内存的反复分配。一个常见的优化做法是给结果键设置合理的过期时间,或者干脆改用ZINTER这类只读命令,把结果交给客户端自行缓存。
最后提醒一点,numkeys参数必须与实际传入的key数量严格一致,WEIGHTS的数量也要匹配,任何不一致都会导致语法错误。在编写封装代码时建议对参数做前置校验,避免线上出现莫名的命令报错。掌握好ZINTERSTORE之后,配合前面提到的权重与聚合策略,排行榜合并、多条件筛选、协同过滤推荐等场景都可以用一条命令优雅地解决。
RedisZINTERSTORE有序集合修改时间:2026-09-04 00:12:56