有序集合没有差集命令
Redis集合中提供了SINTER、SUNION、SDIFF命令分别用来处理集合的交集、并集、差集运算。
有序集合中提供了ZINTERSTORE、ZUNIONSTORE命令分别用来处理有序集合的交集、并集运算。却没有提供用来处理有序集合差集的命令。
项目中用到Redis的有序集合来存储数据,需要对有序集合进行差集运算,在网上看到这篇文章:redis有序集合求差集 zdiff? 提供的解决方法,在此记录下。
解决思路
先使用ZUNIONSTORE计算并集,并设置并集后成员分数权重。
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
再使用ZREMRANGEBYSCORE去除分数为0的成员。
ZREMRANGEBYSCORE key min max
栗子
先添加两个有序集合chinese和english:
127.0.0.1:6379> ZADD chinese 100 user1 99 user2 98 user3
(integer) 3
127.0.0.1:6379> ZADD english 97 user3 96 user4 95 user5
(integer) 3
127.0.0.1:6379> ZRANGE chinese 0 10 WITHSCORES
1) "user3"
2) "98"
3) "user2"
4) "99"
5) "user1"
6) "100"
127.0.0.1:6379> ZRANGE english 0 10 WITHSCORES
1) "user5"
2) "95"
3) "user4"
4) "96"
5) "user3"
6) "97"
再对有序集合chinese和english进行并集运算:
127.0.0.1:6379> ZUNIONSTORE result 2 chinese english WEIGHTS 1 0 AGGREGATE MIN
(integer) 5
127.0.0.1:6379> ZRANGE result 0 10 WITHSCORES
1) "user3"
2) "0"
3) "user4"
4) "0"
5) "user5"
6) "0"
7) "user2"
8) "99"
9) "user1"
10) "100"
这里有必要对ZUNIONSTORE的WEIGHTS和AGGREGATE选项进行说明一番:
WEIGHTS选项可以为每个给定的有序集合分别指定一个乘法因子(Multiplication Factor)。每个给定的有序集合的所有成员的分数在传递给聚合函数(Aggregation Function)之前都要先乘以该有序集合的因子。默认值为1。AGGREGATE选项指定并集运算结果的聚合方式。默认值为SUM,即将所有相同成员的分数相加。当值为MIN或MAX时,则取所有相同成员的分数的最小值或最大值。
有序集合chinese的权重设置为1,所以合并后user1和user2的分数和合并前一样。有序集合english的权重设置为0,所以合并后user4和user5的分数变为0。至于user3的分数,chinese为98,english为0,由于AGGREGATE值为MIN,所以取最小值0。
最后移除有序集合result中分数为0的成员:
127.0.0.1:6379> ZREMRANGEBYSCORE result 0 0
(integer) 3
127.0.0.1:6379> ZRANGE result 0 10 WITHSCORES
1) "user2"
2) "99"
3) "user1"
4) "100"
现在有序集合result就为chinese和english进行差集运算的结果。