redis:zset有序集合命令和内部编码
个人主页 : 个人主页
个人专栏 : 《数据结构》 《C语言》《C++》《Linux》《网络》 《redis学习笔记》
文章目录
- 前言
- 命令
- ZADD
- ZRANGE
- ZREVRANGE
- ZCARD
- ZCOUNT
- ZPOPMAX
- BZPOPMAX
- ZPOPMIN
- BZPOPMIN
- ZRANK
- ZSCORE
- ZREM
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZINCRBY
- 集合间操作
- ZINTERSTORE
- ZUNIONSTORE
- 内部编码
- 总结
前言
有序集合(zset)是redis提供的一种特殊集合类型,结合了集合(元素不能重复)和有序链表(元素有序)的特性;在有序集合中,每一个元素(member)都关联着一个分数(score),这个分数是双精度浮点数,用于对元素进行排序(按照升序的方式进行排列)。
注意:元素不能重复,但分数可以重复;相同分数的元素按照字典序排序
有序集合提供了获取指定分数和元素范围查找,计算成员排名等功能。
命令
ZADD
添加或者更新指定的元素以及关联的分数到zset中,分数应该符合 double 类型,+inf/-inf(正无穷/负无穷)作为正负极限也是合法的
ZADD key [NX | XX] [CH] [INCR] score member [score member … ]
返回值:本次添加成功的元素个数
时间复杂度:O(logN),由于zset是有序结构,要求新增的元素,要放到合适的位置上(需要遍历),而zset内部的数据结构主要是跳表
ZADD相关选项:
- NX:仅在成员不存在时才添加;如果指定的成员已经存在于有序集合中,则不会执行添加操作,并且命令会返回0;可以用于确保集合中成员的唯一性
- XX:仅在成员已经存在时才更新;如果指定的成员不存在与有序集合中,则不会执行任何操作;如果成员存在,则更新其分数
- CH:返回发送变化的成员数量;当使用该选项时,ZADD命令会返回成功添加和更新的成员数量
- INCR:对成员的分数进行增加;指定成员已经存在,则将其分数增加指定的增量值;如果成员不存在,则将其添加到集合中,并以增量值作为起始分数。
添加 CH 选项
添加 XX 选项
添加 NX 选项
添加 INCR选项
ZRANGE
返回指定区间里的元素,分数按照升序排列;带上 WITHSCORES可以把分数返回
ZRANGE key start stop [WITHSCORES]
此处 [start, stop] 为下表构成的区间;有序集合,本身元素就是有先后顺序的,明确区分谁在前,谁在后,因此可以给这个有序集合赋予下标
返回值:区间内的元素列表
时间复杂度:O(logN + M),logN为查找到下标 start 元素的时间消耗,M 是遍历区间的时间消耗
注意:
如果修改的分数,影响到之前的顺序,就会自动的移动元素位置,保持原有的升序顺序不变
ZREVRANGE
返回指定区间里的元素,分数按照降序排列;带上 WITHSCORES可以把分数返回
ZREVRANGE key start stop [WITHSCORES]
返回值:区间内的元素列表
时间复杂度:O(logN + M)
ZCARD
获取一个zset的基数(cardinality),即zset中的元素个数
ZCARD key
返回值:zset内的元素个数
时间复杂度:O(1)
ZCOUNT
返回分数在 min 和 max 之间的元素个数,默认情况下是闭区间,可以通过 “(” 来排除边界
ZCOUNT key min max
返回值:满足条件的元素列表个数
时间复杂度:O(logN);实际上,zset内部会记录每个元素当前的次序;查询到元素(logN),这样直接知道元素所在的次序,可以直接把max对应的元素次序和min对应的元素次序,做减法知道满足条件的元素个数。
ZPOPMAX
删除并返回分数最高的 count 个元素,count默认为一个
ZPOOPMAX key [count]
返回值:被删除的分数和元素列表
时间复杂度:O(logN * M),logN为查询最大值元素,M为删除元素个数
注意:在有序集合中(升序),最大值相当于最后一个元素,删除最大值就是尾删
BZPOPMAX
删除并返回分数最高的元素;如果指定的有序集合为空,该命令阻塞,直到有元素被添加到集合中或者超时发送
BZPOPMAX key [key …] timeout
返回值:被删除的分数和元素列表
时间复杂度:O(logN),logN为查询最大值元素
在阻塞行为上zset的阻塞命令与list阻塞命令相似。
ZPOPMIN
删除并返回分数最低的count个元素
ZPOPMIN key [count]
返回值:删除的分数和元素列表
时间复杂度:O(logN * M),logN为查找分数最低的元素,M为删除元素的个数
注意:在有序集合中(升序),最小值相当于第一个元素,删除最小值就是头删
BZPOPMIN
删除并返回分数最低的元素;如果指定的有序集合为空,该命令阻塞,直到有元素被添加到集合中或者超时发送
BZPOPMIN key [key …] timeout
返回值:删除的分数和元素列表
时间复杂度:O(logN),logN为查找分数最低的元素
ZRANK
返回指定元素的排名,按照升序
ZRANK key member
返回值:指定元素的排名
时间复杂度:O(logN),logN为查找指定元素
ZSCORE
返回指定元素的分数
ZSCORE key member
返回值:指定元素的分数
时间复杂度:O(1),执行ZSCORE命令时,redis首先使用哈希表来快速定位到指定的元素,然后直接从哈希表中获取与该元素关联的分数。
注意:
zset有序集合是通过哈希表和跳表来实现的,哈希表用于快速查找元素是否存在,而跳表则用于维护元素的有序性并支持范围查询
ZREM
删除指定的元素
ZREM key member [member …]
返回值:本次操作删除的元素个数
时间复杂度:O(MlogN),M为参数中member的个数,N为整个有序集合元素的个数
ZREMRANGEBYRANK
按照排序,升序删除指定范围的元素,闭区间
ZREMRANGEBYRANK key start stop
返回值:本次操作删除的元素个数
时间复杂度:O(logN + M),N为整个有序集合的元素个数,M是|start - stop|区间的元素个数,只需要查找一次位置即可
ZREMRANGEBYSCORE
按照分数删除指定范围的元素,闭区间
ZREMRANGEBYSCORE key min max
返回值:本次操作删除的元素个数
时间复杂度:O(logN + M)
"("表示排除边界值
ZINCRBY
为指定的元素的关联分数添加指定的分数值
ZINCRBY key increment member
返回值:增加后元素的分数
时间复杂度:O(logN),logN为查找指定元素
ZINCRBY不仅会修改分数内容,也能同时移动元素位置,保持整个有序集合的有序
集合间操作
ZINTERSTORE
求出给定有序集合中元素的交集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,远山对应的分数按照不同的聚合方式和权重等到新的分数
ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE <SUM | MIN | MAX>]
返回值:目标集合中的元素个数
时间复杂度:O(N * K) + O(M * logM),N是输入的有序集合中,最小的有序集合的元素个数;K是输入了几个有序集合;M是最终结果的有序集合的元素个数
- destination 有序集合的键名,用于存储交集操作的结果;如果指定的键已存在,会被覆盖
- numkeys 一个整数,表示接下来要指定的有序集合键(key) 的数量
- [WEIGHTS weight [weight]] 允许为每个输入有序集合的成员指定一个权重,这些权重在计算交集成员的分数时使用,权重默认为1;权重的数量必须与输入集合的数量相匹配
- [AGGREGATE <SUM | MIN | MAX>] 当输入有序集合的成员在交集操作中有相同的元素时,旋转如何处理这些成员的分数;SUM将具有相同元素的成员的分数相加(默认行为),MIN使用相同元素的成员中的最小分数,MAX使用相同元素的成员中最大分数
两个有序集合user:ranking:1 和 user:ranking:2
使用SUM处理相同元素的分数
使用MAX处理相同元素的分数
使用MIN处理相同元素的分数
给user:ranking:1指定的权重为0.5,user:ranking:2指定的权重为2,使用SUM处理相同元素的分数
ZUNIONSTORE
求出给定有序集合中元素的并集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,元素对应的分数按照聚合方式和权重等到新的分数
ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE <SUM | MIN | MAX>]
返回值:目标集合中的元素个数
时间复杂度:O(N) + O(MkogM) N是输入有序集合总的元素个数,M是最终结果的有序集合的元素个数
选项与ZINTERSTORE一样
给user:ranking:1指定的权重为2,user:ranking:2指定的权重为3,使用SUM处理相同元素的分数
内部编码
有序集合类型的内部编码有两种:
- ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置,同时每个元素的值都小于zset-max-ziplist-value配置时,redis会使用ziplist作为有序集合的内部实现
- skiplist(跳表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现
总的来说就是,如果有序集合的元素个数较少,或者单个元素体积较小,使用ziplist来存储;如果有序集合的元素个数比较多,或者单个元素体积非常大,使用skiplist来存储
总结
以上就是我的redis学习笔记