1.有序集合的定义
有序集合保留了集合不能有重复成员的特性,有序集合中的元素可以排序。
但是它和列表使用索引下表作为排序依据不同的是,它给每个元素设置
一个分数作为排序的依据。
有序集合中元素不能重复,但是score可以重复。
列表:可以重复,有序,有索引下表。应用场景:时间轴,消息队列。
集合:不重复,无序,无下标。应用场景:标签,社交等
有序集合:不重复,有序,有分值。应用场景:排行榜系统,社交等 。
2.集合的使用
(1)添加成员
--返回添加个数
192.168.1.51:6379> zadd user:ranking 251 tom
(integer) 1
192.168.1.51:6379> zadd user:ranking 1 kris 91 mike 200 frank 220 tim 250 martin
(integer) 5
redis3.2为zadd命令添加了 nx,xx,ch,incr 四个选项。
nx:member必须不存在,才可以设置成功,用于添加 。
xx:member必须存在,才可以设置成功,用于更新。
ch:返回此次操作后,有序集合元素和分数发生变化的个数。
incr:对score做增加,相当于zincrby
有序集合相比集合提供了排序字段,但是也产生了代价。
(2)计算成员个数
192.168.1.51:6379> zcard user:ranking
(integer) 6
(3)计算某个成员的分数
192.168.1.51:6379> zscore user:ranking martin
"250"
(4)计算成员排名
--第四名
192.168.1.51:6379> zrank user:ranking martin
(integer) 4
192.168.1.51:6379> zrevrank user:ranking martin
(integer) 1
zrank是从分数从低到高返回排名,zrevrank从高到低。
(5)删除成员
--删除martin
192.168.1.51:6379> zrem user:ranking martin
(integer) 1
(6)增加成员分数
--给tom增加9分,变成了260分。
192.168.1.51:6379> zincrby user:ranking 9 tom
"260"
(7)返回指定排名成员。
--从低到高返回成绩最低的三个成员。
192.168.1.51:6379> zrange user:ranking 0 2 withscores
1) "kris"
2) "1"
3) "mike"
4) "91"
5) "frank"
6) "200"
--从高到低显示成绩最好的三个人。
192.168.1.51:6379> zrevrange user:ranking 0 2
1) "tom"
2) "tim"
3) "frank"
192.168.1.51:6379> zrevrange user:ranking 0 2 withscores
1) "tom"
2) "260"
3) "tim"
4) "220"
5) "frank"
6) "200"
(8)返回指定分数范围的成员
--200到221分之间的人。
192.168.1.51:6379> zrangebyscore user:ranking 200 221 withscores
1) "frank"
2) "200"
3) "tim"
4) "220"
--从高到低未输出值。可能存在bug;
192.168.1.51:6379> zrevrangebyscore user:ranking 200 221 withscores
(empty list or set)
同时min和max还支持开区间(小括号)和闭区间(中括号),
-inf和+inf 分别代表无限小和无限大。
--从小到大去200到无穷大的值。
192.168.1.51:6379> zrangebyscore user:ranking (200 +inf withscores
1) "tim"
2) "220"
3) "tom"
4) "260"
--没有小括号就是闭区间,有小括号就是开区间。
192.168.1.51:6379> zrangebyscore user:ranking 200 +inf withscores
1) "frank"
2) "200"
3) "tim"
4) "220"
5) "tom"
6) "260"
(9)返回指定分数范围成员个数
--200到300分之间的人数。
192.168.1.51:6379> zcount user:ranking 200 300
(integer) 3
(10)删除指定排名内的升序元素
zremrangebyrank user:ranking 0 2
--删除前三名
192.168.1.51:6379> zremrangebyrank user:ranking 0 2
(integer) 3
(11)删除指定分数范围的成员
--删除大于250的。
192.168.1.51:6379> zremrangebyscore user:ranking (250 +inf
(integer) 1
3.集合间的操作。
zadd user:ranking:1 1 kris 91 mike 200 frank 220 tim 250 martin 251 tom
zadd user:ranking:2 8 james 77 mike 625 martin 888 tom
(1)交集
zinterstore destination numkeys key [key] [weight weight] [aggregate sum|min|max]
destination:交集计算结果保存到这个键。
numkeys:有几个键做交集计算。
key:需要做交集的键
weight:每个键的权重,在做交集计算时,每个键中的每个member会将自己的分数乘以这个权重,
每个键的权重默认是1;
aggregate sum|min|max:计算成员交集后分值可以按照sum,min,max做汇总。默认是sum;
--user:ranking:2 的权重是0.5,使用max聚合。
192.168.1.51:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1 user:ranking:2 weights 1 0.5 aggregate max
(integer) 3
192.168.1.51:6379> zrange user:ranking:1_inter_2 0 -1 withscores
1) "mike"
2) "91"
3) "martin"
4) "312.5"
5) "tom"
6) "444"
--按照默认的权重1,做sum聚合。
192.168.1.51:6379> zinterstore user:ranking:1_inter_2_1 2 user:ranking:1 user:ranking:2
(integer) 3
192.168.1.51:6379> zrange user:ranking:1_inter_2_1 0 -1 withscores
1) "mike"
2) "168"
3) "martin"
4) "875"
5) "tom"
6) "1139"
(2)并集
192.168.1.51:6379> zunionstore user:ranking:1_union_2 2 user:ranking:1 user:ranking:2
(integer) 7
--2个键做并集,结束后,sum求和。
192.168.1.51:6379> zrange user:ranking:1_union_2 0 -1 withscores
1) "kris"
2) "1"
3) "james"
4) "8"
5) "mike"
6) "168"
7) "frank"
8) "200"
9) "tim"
10) "220"
11) "martin"
12) "875"
13) "tom"
14) "1139" --这里重复值做了求和处理。
开发时需要注意时间复杂度,防止由于使用不当造成的应用程序效率
下降以及redis阻塞。
4.内部编码
有序集合类型内部编码有两种
ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries
(默认128个),同时每个元素的值都小于zset-max-ziplist-value 配置(默认64字节)
时,redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存的使用。
skiplist(跳跃表):当ziplist条件不满足时,有序集合使用skiplist作为内部实现。
因为此时ziplist的读写效率会下降。
当元素个数少于128个,内部编码为ziplist;
元素个数大于128个时,内部编码为skiplist;
当某个元素的个数大于64字节时,内部编码也会变成skiplist;
5.有序集合的使用场景。
有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频
做排行榜,榜单的维度可能是多个方面的:按时间,按照播放量,按照获得的赞数。
(1)mike获得三个赞。
192.168.1.7:6379> zadd user:ranking:20240619 3 mike
(integer) 1
(2)又获得一个赞。
--累计四个赞了。
192.168.1.7:6379> zincrby user:ranking:20240619 1 mike
"4"
(3)展示获取赞数最多的10个用户
--按照从大到小排序。
192.168.1.7:6379> zrevrangebyscore user:ranking:20240619 9 0
1) "mike"