Redis:zset类型
- zset命令
- ZADD
- ZCARD
- ZCOUNT
- ZRANGE
- ZREVRANGE
- ZRANGEBYSCORE
- ZREVRANGEBYSCORE
- ZPOPMAX
- BZPOPMAX
- ZPOPMIN
- BZPOPMIN
- ZRANK
- ZREVRANK
- ZSCORE
- ZREM
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZINCRBY
- 集合间操作
- ZINRERSTORE
- ZUNIONSTORE
- 内部编码
- ziplist
- skiplist
在Redis
中,有两种集合类型,set
和zset
,其中set
是无序集合,zset
是有序集合,本博客讲解Redis
中的有序集合。
在有序集合中,要按照一定的指标给集合元素进行排序,Redis
个每个集合的元素引入了一个score
属性,这是一个双精度浮点型,每次排序的时候,依据socre
的大小进行排序。如果分数相同,那么以字典序排序。
zset命令
ZADD
- 往
zset
中添加元素和分数
zadd key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
选项:
[XX|NX]
XX
:只更新,如果element
或者key
不存在,操作失败NX
:只添加,如果element
或者key
不存在,添加数据,如果存在,操作失败
[GT|LT]
LT
:如果新的socre
小于(Less Than
)当前的score
,那么更新元素GT
:如果新的socre
大于(Greater Than
)当前的score
,那么更新元素
[CH]
不加CH
:zadd
返回新增的元素个数加CH
:zadd
返回修改的元素个数
[INCR]
:对现有的socre
进行运算
示例:
此处插入了四个数据,随后通过zrange
查询结果(后面讲),可以看到输出结果是以score
排序的。
还可以通过zadd
更新数值,把mike
的值提升到80.5
后,再次查询顺序就变了。
此处演示ch
的功能,第一次先通过add
添加了两个成员lora
和meg
。第二次修改lora
和meg
的score
,结果返回值为0
,这不是说明修改失败了,而是其只返回新增元素个数,而不是修改的元素个数。第三次修改lora
和meg
的score
,并且加入ch
选项,返回2
说明有两个元素修改成功了。
第一次通过zadd
设置peter
的score
为100
,第二次添加incr
选项,表示在当前的score
基础上再加20
,返回120
为增加后的结果。
ZCARD
- 获取
zset
的元素个数
zcard key
返回zset
的元素个数。
ZCOUNT
- 返回指定区间内的元素个数
zcount key min max
返回score
在[min, max]
闭区间的元素个数,可以通过(min (max
来设置开区间。
在zset3
中,有五个分数12 20 42 68 88
。第一次查询20 68
,在闭区间内有三个数值,返回3
。第二次查询(20 68
,表示左开右闭区间,第三次查询(20 (68
表示开区间,第四次查询20 (68
表示左闭右开区间。
此处实现计数,不是查询到min
和max
后,遍历区间内的元素然后计数。在zset
内部,会给每个元素存储其当前的排名,查询到min
和max
后,直接将两者的排名做差就可以得到count
。
另外的,区间还支持浮点数的负无穷大-inf
和正无穷大inf
。
这种格式就是统计zset
中所有元素个数。
ZRANGE
- 返回指定区间内的元素,按升序排序
zrange key start stop [withscores]
按升序返回[start, stop]
区间内的元素,如果带上withscores
则将score
一起返回。
此处的start
和stop
不是分数,而是元素的排名,从0
开始,支持负数。
示例:
加上withcores
参数后,每个元素的下一行是它的socre
。
ZREVRANGE
- 返回指定区间内的元素,按降序排序
zrevrange key start stop [withscores]
按降序返回[start, stop]
区间内的元素,如果带上withscores
则将score
一起返回。
此处的rev
表示reverse
翻转,只是将原先的输出顺序颠倒了一下,用法和zrange
没有区别。
ZRANGEBYSCORE
- 返回指定区间内的元素,按升序排序
zrangebyscore key min max [withscores]
按升序返回score
在[min, max]
区间内的元素,如果带上withscores
则将score
一起返回。
之前的zrange
是通过元素排名返回,zrangebyscore
则是通过score
区间返回。
示例:
注意:官方文档表明,该命令即将被废弃,并且功能会合并到zrange
中。
ZREVRANGEBYSCORE
- 返回指定区间内的元素,按降序排序
zrevrangebyscore key min max [withscores]
按降序返回score
在[min, max]
区间内的元素,如果带上withscores
则将score
一起返回。
只是将输出顺序颠倒了一下,用法和zrangebyscore
一样。
注意:官方文档表明,该命令即将被废弃,并且功能会合并到zrevrange
中。
ZPOPMAX
- 获取并删除
score
最高的多个元素
zpopmax key [count]
返回当前的count
个最大元素,并且将这些元素从zset
中删除。
示例:
如果多个元素的score
相同,那么会按照member
的字典序进行比较,字典序高的先删除。
BZPOPMAX
- 读取并删除
zset
最大元素,如果没有元素则陷入阻塞
bzpopmax key [key ...] timeout
bzpopmax
可以同时指定多个key
,也就是多个zset
,只要任何一个zset
有数据,就返回结果。还可以设置超时时间timeout
,以秒为单位,如果超过时间了,返回nil
。
如果超时时间设置为0
,则一直阻塞,不会超时。
示例:
此处启动了两个终端,左侧终端通过bzpopmax
读取zset1
的最大值。但是由于zset1
内没有元素陷入阻塞。不久后在右侧终端插入66 lisa
,此时左侧终端检测到后,立刻返回结果。zset1
表示自己读取到的数据属于哪一个zset
,lisa
是member
,66
是score
。
ZPOPMIN
- 获取并删除
score
最小的多个元素
zpopmin key [count]
返回当前的count
个最小元素,并且将这些元素从zset
中删除。
BZPOPMIN
- 读取并删除
zset
最小元素,如果没有元素则陷入阻塞
bzpopmin key [key ...] timeout
bzpopmin
可以同时指定多个key
,也就是多个zset
,只要任何一个zset
有数据,就返回结果。还可以设置超时时间timeout
,以秒为单位,如果超过时间了,返回nil
。
如果超时时间设置为0
,则一直阻塞,不会超时。
ZRANK
- 获取指定元素的排名
zrank key member
返回指定元素member
的排名,这个排名就是socre
从小到大的顺序,从0
开始排,也可以当作下标。
示例:
此处排名最前的是lisa
,下标为0
。
ZREVRANK
- 获取指定元素的排名
zrevrank key member
返回指定元素member
的排名,这个排名就是socre
从大到小的顺序,从0
开始排。
示例:
ZSCORE
- 获取指定元素的分数
zscore key member
返回指定元素member
的分数。
ZREM
- 删除指定元素
zrem key member [member ...]
返回成功删除的元素个数。
ZREMRANGEBYRANK
- 根据排名,删除指定区间内的元素
zremrangebyrank key start stop
删除排名在[start, stop]
闭区间范围内的元素,返回成功删除的元素个数。
示例:
ZREMRANGEBYSCORE
- 根据
score
,删除指定区间内的元素
zremrangebyscore key min max
删除分数在[min, max]
闭区间范围内的元素,返回成功删除的元素个数。
示例:
ZINCRBY
- 为指定元素的
score
增加指定的值
zincrby key increment member
给member
的score
增加increment
的值,返回增加后的结果,increment
可以为负值和浮点数。
集合间操作
在set
中,提供了sinter
、sunion
、sdiff
处理交集、并集、差集。那么zset
是否也有对应的zinter
、zunion
、zdiff
?是有的,但是在Redis 6.2
后才开始支持,在那之前,zset
只提供了两个集合间操作。
ZINRERSTORE
- 求多个集合的交集,结果保存到指定
zset
中
zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate <sum | min | max>]
destination
:输出结果到给zset
中numkeys
:指定后续输入的key
的个数weights
:权重,每一个zset
都配一个weight
,计算时score
乘对应的weight
aggreate
:score
的合并方式sum
:求和(默认值)min
:取最小max
:取最大
示例:
此处创建了两个zset
,通过zinterstore
合并,其中zset1
的权重是1
,zset2
的权重是100
,以sum
方式合并。最后求出交集bob 1 * 100 + 20
,lisa 3 * 100 + 12
。
ZUNIONSTORE
- 求多个集合的并集,结果保存到指定
zset
中
zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate <sum | min | max>]
这个参数和zinterstore
完全一致,只是从交集变成并集。
- 总结:
命令 | 功能 |
---|---|
zadd | 往zset 中添加元素和分数 |
zcard | 获取zset 的元素个数 |
zcount | 计算在指定分数范围内的元素个数 |
zrange | 获取指定区间内的元素 |
zrevrange | 获取指定区间内的元素(按分数从高到低) |
zrangebyscore | 获取指定分数范围内的元素 |
zrevrangebyscore | 获取指定分数范围内的元素(按分数从高到低) |
zpopmax | 弹出zset 中分数最高的元素 |
bzpopmax | 阻塞弹出zset 中分数最高的元素 |
zpopmin | 弹出zset 中分数最低的元素 |
bzpopmin | 阻塞弹出zset 中分数最低的元素 |
zrank | 获取元素在zset 中的排名(按分数从小到大) |
zrevrank | 获取元素在zset 中的排名(按分数从大到小) |
zscore | 获取元素在zset 中的分数 |
zrem | 移除zset 中的一个或多个元素 |
zremrangebyrank | 移除zset 中给定排名区间的元素 |
zremrangebyscore | 移除zset 中给定分数区间的元素 |
zincrby | 增加zset 中元素的分数 |
zinterstore | 计算两个或多个zset 的交集,并将结果存储在新的zset 中 |
zunionstore | 计算两个或多个zset 的并集,并将结果存储在新的zset 中 |
内部编码
ziplist
当有序集合的元素个数小于zset-max-ziplist-entries
配置(默认128个),同时每个元素的值都⼩于zset-max-ziplist-value
配置(默认64字节)时,Redis
会用ziplist
来作为有序集合的内部实现,ziplist
可以有效减少内存的使⽤。
skiplist
当ziplist条件不满⾜时,有序集合会使用skiplist
作为内部实现,因为此时ziplist
的操作效率会下降。
跳表是一种搜索结构,搜索时间复杂度为O(lgN)
,与平衡二叉搜索树是一个级别。