当前位置:网站首页>Redis入门完整教程:有序集合详解
Redis入门完整教程:有序集合详解
2022-07-04 22:29:00 【谷哥学术】
有序集合相对于哈希、列表、集合来说会有一点点陌生,但既然叫有序
集合,那么它和集合必然有着联系,它保留了集合不能有重复成员的特性,
但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下标作为
排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依
据。如图2-24所示,该有序集合包含kris、mike、frank、tim、martin、tom,
它们的分数分别是1、91、200、220、250、251,有序集合提供了获取指定
分数和元素范围查询、计算成员排名等功能,合理的利用有序集合,能帮助
我们在实际开发中解决很多问题。
有序集合中的元素不能重复,但是score可以重复,就和一个班里的同
学学号不能重复,但是考试成绩可以相同。
表2-7给出了列表、集合、有序集合三者的异同点。
2.6.1 命令
本节依旧按照集合内和集合外两个维度对有序集合的命令进行介绍。
1.集合内
(1)添加成员
zadd key score member [score member ...]
下面操作向有序集合user:ranking添加用户tom和他的分数251:
127.0.0.1:6379> zadd user:ranking 251 tom
(integer) 1
返回结果代表成功添加成员的个数:
127.0.0.1:6379> zadd user:ranking 1 kris 91 mike 200 frank 220 tim 250 martin
(integer) 5
有关zadd命令有两点需要注意:
·Redis3.2为zadd命令添加了nx、xx、ch、incr四个选项:
·nx:member必须不存在,才可以设置成功,用于添加。
·xx:member必须存在,才可以设置成功,用于更新。
·ch:返回此次操作后,有序集合元素和分数发生变化的个数
·incr:对score做增加,相当于后面介绍的zincrby。
·有序集合相比集合提供了排序字段,但是也产生了代价,zadd的时间
复杂度为O(log(n)),sadd的时间复杂度为O(1)。
(2)计算成员个数
zcard key
例如下面操作返回有序集合user:ranking的成员数为5,和集合类型的
scard命令一样,zcard的时间复杂度为O(1)。
127.0.0.1:6379> zcard user:ranking
(integer) 5
(3)计算某个成员的分数
zscore key member
tom的分数为251,如果成员不存在则返回nil:
127.0.0.1:6379> zscore user:ranking tom
"251"
127.0.0.1:6379> zscore user:ranking test
(nil)
(4)计算成员的排名
zrank key member
zrevrank key member
zrank是从分数从低到高返回排名,zrevrank反之。例如下面操作中,tom
在zrank和zrevrank分别排名第5和第0(排名从0开始计算)。
127.0.0.1:6379> zrank user:ranking tom
(integer) 5
127.0.0.1:6379> zrevrank user:ranking tom
(integer) 0
(5)删除成员
zrem key member [member ...]
下面操作将成员mike从有序集合user:ranking中删除。
127.0.0.1:6379> zrem user:ranking mike
(integer) 1
返回结果为成功删除的个数。
(6)增加成员的分数
zincrby key increment member
下面操作给tom增加了9分,分数变为了260分:
127.0.0.1:6379> zincrby user:ranking 9 tom
"260"
(7)返回指定排名范围的成员
zrange key start end [withscores]
zrevrange key start end [withscores]
有序集合是按照分值排名的,zrange是从低到高返回,zrevrange反之。
下面代码返回排名最低的是三个成员,如果加上withscores选项,同时会返
回成员的分数:
127.0.0.1:6379> zrange user:ranking 0 2 withscores
1) "kris"
2) "1"
3) "frank"
4) "200"
5) "tim"
6) "220"
127.0.0.1:6379> zrevrange user:ranking 0 2 withscores
1) "tom"
2) "260"
3) "martin"
4) "250"
5) "tim"
6) "220"
(8)返回指定分数范围的成员
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]
其中zrangebyscore按照分数从低到高返回,zrevrangebyscore反之。例如
下面操作从低到高返回200到221分的成员,withscores选项会同时返回每个
成员的分数。[limit offset count]选项可以限制输出的起始位置和个数:
127.0.0.1:6379> zrangebyscore user:ranking 200 tinf withscores
1) "frank"
2) "200"
3) "tim"
4) "220"
127.0.0.1:6379> zrevrangebyscore user:ranking 221 200 withscores
1) "tim"
2) "220"
3) "frank"
4) "200"
同时min和max还支持开区间(小括号)和闭区间(中括号),-inf和
+inf分别代表无限小和无限大:
127.0.0.1:6379> zrangebyscore user:ranking (200 +inf withscores
1) "tim"
2) "220"
3) "martin"
4) "250"
5) "tom"
6) "260"
(9)返回指定分数范围成员个数
zcount key min max
下面操作返回200到221分的成员的个数:
127.0.0.1:6379> zcount user:ranking 200 221
(integer) 2
(10)删除指定排名内的升序元素
zremrangebyrank key start end
下面操作删除第start到第end名的成员:
127.0.0.1:6379> zremrangebyrank user:ranking 0 2
(integer) 3
(11)删除指定分数范围的成员
zremrangebyscore key min max
下面操作将250分以上的成员全部删除,返回结果为成功删除的个数:
127.0.0.1:6379> zremrangebyscore user:ranking (250 +inf
(integer) 2
2.集合间的操作
将图2-25的两个有序集合导入到Redis中。
127.0.0.1:6379> zadd user:ranking:1 1 kris 91 mike 200 frank 220 tim 250 martin
251 tom
(integer) 6
127.0.0.1:6379> zadd user:ranking:2 8 james 77 mike 625 martin 888 tom
(integer) 4
(1)交集
zinterstore destination numkeys key [key ...] [weights weight [weight ...]]
[aggregate sum|min|max]
这个命令参数较多,下面分别进行说明:
·destination:交集计算结果保存到这个键。
·numkeys:需要做交集计算键的个数。
·key[key...]:需要做交集计算的键。
·weights weight[weight...]:每个键的权重,在做交集计算时,每个键中
的每个member会将自己分数乘以这个权重,每个键的权重默认是1。
·aggregate sum|min|max:计算成员交集后,分值可以按照sum(和)、
min(最小值)、max(最大值)做汇总,默认值是sum。
下面操作对user:ranking:1和user:ranking:2做交集,weights和
aggregate使用了默认配置,可以看到目标键user:ranking:1_inter_2对分值
做了sum操作:
127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1
user:ranking:2
(integer) 3
127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
1) "mike"
2) "168"
3) "martin"
4) "875"
5) "tom"
6) "1139"
如果想让user:ranking:2的权重变为0.5,并且聚合效果使用max,可以
执行如下操作:
127.0.0.1:6379> zinterstore user:ranking:1_inter_2 2 user:ranking:1
user:ranking:2 weights 1 0.5 aggregate max
(integer) 3
127.0.0.1:6379> zrange user:ranking:1_inter_2 0 -1 withscores
1) "mike"
2) "91"
3) "martin"
4) "312.5"
5) "tom"
6) "444"
(2)并集
zunionstore destination numkeys key [key ...] [weights weight [weight ...]]
[aggregate sum|min|max]
该命令的所有参数和zinterstore是一致的,只不过是做并集计算,例如
下面操作是计算user:ranking:1和user:ranking:2的并集,weights和
aggregate使用了默认配置,可以看到目标键user:ranking:1_union_2对分值
做了sum操作:
127.0.0.1:6379> zunionstore user:ranking:1_union_2 2 user:ranking:1
user:ranking:2
(integer) 7
127.0.0.1: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"
至此有序集合的命令基本介绍完了,表2-8是这些命令的时间复杂度,
开发人员在使用对应的命令进行开发时,不仅要考虑功能性,还要了解相应
的时间复杂度,防止由于使用不当造成应用方效率下降以及Redis阻塞。
2.6.2 内部编码
有序集合类型的内部编码有两种:
·ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-
entries配置(默认128个),同时每个元素的值都小于zset-max-ziplist-value配
置(默认64字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist
可以有效减少内存的使用。
·skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作
为内部实现,因为此时ziplist的读写效率会下降。
下面用示例来说明:
1)当元素个数较少且每个元素较小时,内部编码为skiplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
(integer) 3
127.0.0.1:6379> object encoding zsetkey
"ziplist"
2.1)当元素个数超过128个,内部编码变为ziplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 12 e4 ... 忽略 ... 84 e129
(integer) 129
127.0.0.1:6379> object encoding zsetkey
"skiplist"
2.2)当某个元素大于64字节时,内部编码也会变为hashtable:
127.0.0.1:6379> zadd zsetkey 20 "one string is bigger than 64 byte.............
..................."
(integer) 1
127.0.0.1:6379> object encoding zsetkey
"skiplist"
2.6.3 使用场景
有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用
户上传的视频做排行榜,榜单的维度可能是多个方面的:按照时间、按照播
放数量、按照获得的赞数。本节使用赞数这个维度,记录每天用户上传视频
的排行榜。主要需要实现以下4个功能。
(1)添加用户赞数
例如用户mike上传了一个视频,并获得了3个赞,可以使用有序集合的
zadd和zincrby功能:
zadd user:ranking:2016_03_15 mike 3
如果之后再获得一个赞,可以使用zincrby:
zincrby user:ranking:2016_03_15 mike 1
(2)取消用户赞数
由于各种原因(例如用户注销、用户作弊)需要将用户删除,此时需要
将用户从榜单中删除掉,可以使用zrem。例如删除成员tom:
zrem user:ranking:2016_03_15 mike
(3)展示获取赞数最多的十个用户
此功能使用zrevrange命令实现:
zrevrangebyrank user:ranking:2016_03_15 0 9
(4)展示用户信息以及用户分数
此功能将用户名作为键后缀,将用户信息保存在哈希类型中,至于用户
的分数和排名可以使用zscore和zrank两个功能:
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike
边栏推荐
- 10 schemes to ensure interface data security
- [the 2023 autumn recruitment of MIHA tour] open [the only exclusive internal push code of school recruitment eytuc]
- Wake up day, how do I step by step towards the road of software testing
- 都说软件测试很简单有手就行,但为何仍有这么多劝退的?
- 醒悟的日子,我是怎么一步一步走向软件测试的道路
- LOGO特训营 第三节 首字母创意手法
- More than 30 institutions jointly launched the digital collection industry initiative. How will it move forward in the future?
- Business is too busy. Is there really no reason to have time for automation?
- Logo special training camp Section IV importance of font design
- Introducing QA into the software development lifecycle is the best practice that engineers should follow
猜你喜欢
Attack and Defense World MISC Advanced Area Erik baleog and Olaf
Close system call analysis - Performance Optimization
Redis sentinel simply looks at the trade-offs between distributed high availability and consistency
攻防世界 MISC 进阶区 Ditf
Logo special training camp section II collocation relationship between words and graphics
[the 2023 autumn recruitment of MIHA tour] open [the only exclusive internal push code of school recruitment eytuc]
How to send a reliable request before closing the page
共创软硬件协同生态:Graphcore IPU与百度飞桨的“联合提交”亮相MLPerf
醒悟的日子,我是怎么一步一步走向软件测试的道路
Sobel filter
随机推荐
Practice and principle of PostgreSQL join
Analog rocker controlled steering gear
Advanced area a of attack and defense world misc Masters_ good_ idea
It is said that software testing is very simple, but why are there so many dissuasions?
攻防世界 MISC 进阶 glance-50
Sword finger offer 67 Convert a string to an integer
Deployment of JVM sandbox repeater
串口数据帧
sobel过滤器
Sword finger offer 65 Add without adding, subtracting, multiplying, dividing
String类中的常用方法
Logo special training camp section III initial creative techniques
Logo special training camp section II collocation relationship between words and graphics
Sword finger offer 68 - ii The nearest common ancestor of binary tree
Microservices -- Opening
Hit the core in the advanced area of misc in the attack and defense world
LOGO特训营 第四节 字体设计的重要性
Three stage operations in the attack and defense drill of the blue team
关于栈区、堆区、全局区、文字常量区、程序代码区
Alibaba launched a new brand "Lingyang" and is committed to becoming a "digital leader"