文章目录
- 常用命令
-
- zadd
- zcard
- zcount
- [zrange && zrevrange](#zrange && zrevrange)
- zrangebyscore
- [zpopmax && bzpopmax](#zpopmax && bzpopmax)
- [zpopmin && zpopmax](#zpopmin && zpopmax)
- [zrank && zrevrank](#zrank && zrevrank)
- zscore
- zrem
- zremrangebyrank
- zremrangebyscore
- zincrby
- 集合间操作
-
- [交集 zinterstore](#交集 zinterstore)
- [并集 zunionstore](#并集 zunionstore)
- 内部编码
- 应用场景

有序集合和集合(Set)一样,不能有重复成员,但与之不同的是,有序集合中的每个元素都有一个唯一的浮点类型的分数(score),通过这个分数实现有序性

有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能
有序集合中的元素是不能重复的,但分数可以相同。若分数相同,则按元素的字典序排序
常用命令
zadd
添加或者更新指定的元素以及关联的分数到 zset ,分数应该符合 double 类型,+inf / -inf 作为正负极限也是合法的
相关选项:
- XX:当元素存在时才生效,即用于更新已经存在的元素,不会添加新元素
- NX:当元素不存在时才生效,即用于添加新元素
- CH:默认情况下,zadd 的返回值时本次新添加的元素个数,使用该选项,返回值还会包含本次操作更新的元素的个数
- INCR:将元素的分数加上指定的分数,可正可负。此时只能指定一个元素和分数
zadd key [NX | XX] [CH] [INCR] score member [score member...]
返回值:本次添加成功的元素;如果使用了 INCR,则返回值为修改后的分数
示例:
lua
127.0.0.1:6379> zadd key1 95 zhangsan 92 lisi 97 wangwu 77 zhaoliu
(integer) 4
127.0.0.1:6379> zadd key1 94 zhangsan
(integer) 0 # 修改默认不计入返回值
# 查看 zset 元素
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "zhangsan"
6) "94"
7) "wangwu"
8) "97"
# 修改并将修改成功的元素个数计入返回值
127.0.0.1:6379> zadd key1 XX CH 99 zhangsan
(integer) 1
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "wangwu"
6) "97"
7) "zhangsan"
8) "99"
# 减少分数
127.0.0.1:6379> zadd key1 incr -4 zhangsan
"95"
zcard
获取 zset 的基数(cardinality),即 zset 中的元素个数
zcard key
返回值:zset 的元素个数
示例:
lua
127.0.0.1:6379> zcard key1
(integer) 4
zcount
返回分数在 min 和 max 之间的元素个数,默认情况下,是包含 min 和 max,但可以通过(
排除
zcount key [(]min [(]max
返回值:满足条件的元素个数
时间复杂度:O(log(N))
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "zhangsan"
6) "95"
7) "wangwu"
8) "97"
# 包含分数 77 和 95
127.0.0.1:6379> zcount key1 77 95
(integer) 3
# 不包含分数 77
127.0.0.1:6379> zcount key1 (77 95
(integer) 2
# 不包含分数 77 和 95
127.0.0.1:6379> zcount key1 (77 (95
(integer) 1
zrange && zrevrange
zrange
返回指定区间的元素,升序
withscores 选项可以把分数也返回
zrange key start stop [withscores]
start, stop\] 为闭区间,下标从0开始,支持负数,-1表示倒数第一个数,以此类推
时间复杂度:O(log(N) + M),N为元素总个数,M为区间元素个数
示例:
lua
# 查询从下标0到最后一个
127.0.0.1:6379> zrange key1 0 -1
1) "zhaoliu"
2) "lisi"
3) "zhangsan"
4) "wangwu"
# 携带上分数
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "zhangsan"
6) "95"
7) "wangwu"
8) "97"
# 查询下标1到3
127.0.0.1:6379> zrange key1 1 3 withscores
1) "lisi"
2) "92"
3) "zhangsan"
4) "95"
5) "wangwu"
6) "97"
zrevrange
返回指定区间的元素,降序
withscores 选项可以携带分数返回
PS:该命令可能在 6.2.0后废弃,功能合并到 zrange 中
zrevrange key start stop [withscores]
时间复杂度:O(log(N) + M),N为元素总个数,M为区间元素个数
示例:
lua
127.0.0.1:6379> zrevrange key1 0 -1 withscores
1) "wangwu"
2) "97"
3) "zhangsan"
4) "95"
5) "lisi"
6) "92"
7) "zhaoliu"
8) "77"
127.0.0.1:6379> zrevrange key1 1 3 withscores
1) "zhangsan"
2) "95"
3) "lisi"
4) "92"
5) "zhaoliu"
6) "77"
zrangebyscore
返回分数在 min 和 max 之间的元素,默认是闭区间,可以通过(
排除
PS:该命令可能在6.2.0后废除,功能合并到 zrange 中
zrangebyscore key min max [withscores]
时间复杂度:O(log(N)+M)
示例:
lua
127.0.0.1:6379> zrangebyscore key1 -inf +inf withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "zhangsan"
6) "95"
7) "wangwu"
8) "97"
127.0.0.1:6379> zrangebyscore key1 (92 +inf withscores
1) "zhangsan"
2) "95"
3) "wangwu"
4) "97"
zpopmax && bzpopmax
zpopmax
删除并返回分数最高的 count 个元素
zpopmax key [count]
时间复杂度:O(log(N) * M),删除一个元素为log(N),M为要删除的元素个数
返回值:分数和元素列表
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
5) "zhangsan"
6) "95"
7) "wangwu"
8) "97"
127.0.0.1:6379> zpopmax key1 2
1) "wangwu"
2) "97"
3) "zhangsan"
4) "95"
bzpopmax
zpopmax 的阻塞版本
bzpopmax key [key...] timeout
时间复杂度:O(log(N));源码虽然有记录最大元素,但还是套用了删除一个元素的算法,所以时间复杂度不是O(1),而是O(log(N))
返回值:zset、元素、分数
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "lisi"
4) "92"
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "wangwu"
2) "100"
127.0.0.1:6379> bzpopmax key1 key2 10
1) "key1"
2) "lisi"
3) "92"
按顺序检查有序集合是否有元素,有则删除最大,无则检查下一个有序集合,只要删除一个元素就结束,所以并不是删除所有有序结合的最大值,而是最先有元素的有序集合的最大值
zpopmin && zpopmax
zpopmin
大致与 zpopmax 相同,不过时删除最小元素
删除并返回分数最低的 count 个元素
zpopmin key [count]
时间复杂度:O(log(N) * M)
返回值:分数和元素列表
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "zhaoliu"
2) "77"
3) "zhangsan"
4) "88"
5) "lisi"
6) "99"
127.0.0.1:6379> zpopmin key1 2
1) "zhaoliu"
2) "77"
3) "zhangsan"
4) "88"
bzpopmin
zpopmin 的阻塞版本
bzpopmin key [key...] timeout
时间复杂度:O(log(N))
返回值:zset、元素、分数
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
(empty array)
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "zhangsan"
2) "95"
3) "wangwu"
4) "100"
127.0.0.1:6379> bzpopmin key1 key2 10
1) "key2"
2) "zhangsan"
3) "95"
zrank && zrevrank
zrank
返回指定元素的排名,升序
zrank key member
时间复杂度:O(log(N))
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "lisi"
2) "48"
3) "wangwu"
4) "83"
5) "zhaoliu"
6) "92"
7) "zhangsan"
8) "94"
127.0.0.1:6379> zrank key1 zhangsan
(integer) 3
127.0.0.1:6379> zrank key1 lisi
(integer) 0
zrevrank
返回指定元素的排名,降序
zrevrank key member
时间复杂度:O(log(N))
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "lisi"
2) "48"
3) "wangwu"
4) "83"
5) "zhaoliu"
6) "92"
7) "zhangsan"
8) "94"
127.0.0.1:6379> zrevrank key1 zhangsan
(integer) 0
127.0.0.1:6379> zrevrank key1 lisi
(integer) 3
zscore
获取指定元素的分数
zscore key member
时间复杂度:O(1)
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "lisi"
2) "48"
3) "wangwu"
4) "83"
5) "zhaoliu"
6) "92"
7) "zhangsan"
8) "94"
127.0.0.1:6379> zscore key1 zhangsan
"94"
127.0.0.1:6379> zscore key1 lisi
"48"
zrem
删除指定的元素
zrem key member [member...]
时间复杂度:O(log(N) * M),删除一个元素为O(log(N)),M为要删除的元素个数
返回值:本次操作删除的元素个数
示例:
lua
127.0.0.1:6379> zrem key1 zhangsan lisi
(integer) 2
zremrangebyrank
按照排序,升序删除指定范围的元素,左闭右闭
zremrangebyrank key start stop
时间复杂度:O(log(N) + M)
返回值:本次操作删除的元素个数
示例:
lua
127.0.0.1:6379> zrange key 0 -1
1) "zhaoliu"
2) "zhangsan"
3) "lisi"
4) "wangwu"
127.0.0.1:6379> zremrangebyrank key 0 1
(integer) 2
127.0.0.1:6379> zrange key 0 -1
1) "lisi"
2) "wangwu"
zremrangebyscore
按照分数删除指定范围的元素,左闭右闭
zremrangebyrank key min max
时间复杂度:O(log(N) + M)
返回值:本次操作删除的元素个数
示例:
lua
127.0.0.1:6379> zrange key 0 -1
1) "lisi"
2) "wangwu"
127.0.0.1:6379> zremrangebyscore key -inf +inf
(integer) 2
zincrby
给指定的元素添加指定分数,可正可负
zincrby key increment member
时间复杂度:O(log(N))
返回值:修改后元素的分数
示例:
lua
127.0.0.1:6379> zadd key 88 zhangsan
(integer) 1
127.0.0.1:6379> zincrby key 8 zhangsan
"96"
127.0.0.1:6379> zincrby key -4 zhangsan
"92"
集合间操作
Zset 提供交集和并集操作
交集 zinterstore
交集时提取多个 Zset 共有的元素,但因为还是分数(score),所以需要指定提取后的分数如何取值。
同时 Zset 还提供权重(weight)
zinterstore destination numkeys key [key...] [weights weight] [aggregate sum | min | max]
- destination:将并集的结果保存在目标 Zset 中
- numkeys:并集的 Zset 个数
- weight:权重,浮点类型,个数应和 numkeys 相同
- aggregate:并集的分数组成,可选 sum | min | max,默认是 sum

时间复杂度:O(N * K) + O(M * log(M));N 是输入的有序集合中,最小的有序集合的元素个数;K是输入了几个有序集合;M是最终结果的有序集合的元素个数
返回值:并集的元素个数
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "c"
2) "2"
3) "a"
4) "5"
5) "b"
6) "8"
7) "d"
8) "14"
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "d"
2) "6"
3) "f"
4) "7"
5) "c"
6) "8"
7) "e"
8) "13"
# 分数默认以 sum
127.0.0.1:6379> zinterstore key3 2 key1 key2
(integer) 2
127.0.0.1:6379> zrange key3 0 -1 withscores
1) "c"
2) "10"
3) "d"
4) "20"
# 分数以 max
127.0.0.1:6379> zinterstore key4 2 key1 key2 aggregate max
(integer) 2
127.0.0.1:6379> zrange key4 0 -1 withscores
1) "c"
2) "8"
3) "d"
4) "14"
# 分数乘以权重
127.0.0.1:6379> zinterstore key5 2 key1 key2 weights 4 6
(integer) 2
127.0.0.1:6379> zrange key5 0 -1 withscores
1) "c"
2) "56"
3) "d"
4) "92"
并集 zunionstore
zunionstore destination numkeys key [key...] [weights weight...] [aggregate sum | min | max]

时间复杂度:O(N) + O(M * log(M));N 是输入的有序集合总的元素个数;M是最终结果的有序集合的元素个数
示例:
lua
127.0.0.1:6379> zrange key1 0 -1 withscores
1) "c"
2) "2"
3) "a"
4) "5"
5) "b"
6) "8"
7) "d"
8) "14"
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "d"
2) "6"
3) "f"
4) "7"
5) "c"
6) "8"
7) "e"
8) "13"
127.0.0.1:6379> zunionstore key3 2 key1 key2
(integer) 6
127.0.0.1:6379> zrange key3 0 -1 withscores
1) "a"
2) "5"
3) "f"
4) "7"
5) "b"
6) "8"
7) "c"
8) "10"
9) "e"
10) "13"
11) "d"
12) "20"
127.0.0.1:6379> zunionstore key4 2 key1 key2 aggregate min
(integer) 6
127.0.0.1:6379> zrange key4 0 -1 withscores
1) "c"
2) "2"
3) "a"
4) "5"
5) "d"
6) "6"
7) "f"
8) "7"
9) "b"
10) "8"
11) "e"
12) "13"
127.0.0.1:6379> zunionstore key5 2 key1 key2 weights 0.2 0.5
(integer) 6
127.0.0.1:6379> zrange key5 0 -1 withscores
1) "a"
2) "1"
3) "b"
4) "1.6000000000000001"
5) "f"
6) "3.5"
7) "c"
8) "4.4000000000000004"
9) "d"
10) "5.8000000000000007"
11) "e"
12) "6.5"

内部编码
有序集合的内部编码有两种:
- ziplist(压缩列表):当有序集合的元素个数小于
zset-max-ziplist-entries
,同时每个元素的值都小于zset-max-ziplist-value
时,ziplist 为其内部实现,可以有效减少内存的使用 - skiplist(跳表):不满足上述条件时,使用 skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降
应用场景
有序集合比较典型的使用场景就是排行榜系统。例如常见的网站上的热榜信息,榜单的维度可能时多方面的:按照时间、阅读量、点赞量。
例如,通过点赞维护热榜
- 添加用户赞数
例如用户 zhangsan 发布了一篇文章,获得了3个点赞,添加使用zadd
,后续获赞使用zincrby
lua
zadd user:ranking:2025-06-02 3 zhangsan
zincrby user:ranking:2025-06-02 2 zhangsan
- 取消用户赞数
由于各种原因(如用户删除文章,作弊),此时需要将用户从榜单删除,使用zrem
lua
zrem user:ranking:2025-06-02 zhangsan
- 展示获赞数最多的10个用户,可以使用
zrevrange
lua
zrevrangebyrank user:ranking:2025-06-02 0 9
- 展示用户信息以及用户分数
lua
zscore user:ranking:2025-06-02 lisi
zrank user:ranking:2025-06-02 lisi
以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。