一: Zset 有序集合
1.1 常用命令
有序集合在 Redis 数据结构中相较于字符串、列表、哈希和集合稍显陌生。它继承了集合中元素不允许重复的特点,但与集合不同的是,有序集合的每个元素都关联一个唯一的浮点分数(score)。通过分数,有序集合中的元素可以按照分数大小进行排序,而不是通过下标。除此之外,有序集合还提供了根据分数或元素范围查找、计算成员排名等功能。合理利用有序集合,可以在实际开发中高效解决排序和排名相关的问题。
数据结构 | 是否允许重复元素 | 是否有序 | 有序依据 | 应用场景 |
---|---|---|---|---|
列表 | 是 | 是 | 索引下标 | 时间轴、消息队列等 |
集合 | 否 | 否 | 无 | 标签、社交等 |
有序集合 | 否 | 是 | 分数 | 排行榜系统、社交等 |
1.1.1 ZADD
ZADD 命令用于向有序集合中添加或更新指定元素及其关联的分数。分数需为 double 类型,正无穷(+inf)和负无穷(-inf)也被视为合法分数,返回值为本次添加成功元素的个数,ZADD 相关选项如下:
选项 | 描述 |
---|---|
XX | 仅用于更新已存在的元素,不会添加新元素。 |
NX | 仅用于添加新元素,不会更新已存在的元素。 |
CH | 默认情况下,ZADD 返回添加的元素个数;指定该选项后,同时返回更新的元素个数。 |
INCR | 将指定元素的分数增加指定值,类似 ZINCRBY 的效果;此时只能指定一个元素和对应分数。 |
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
ZADD myzset 1 "one"
(integer) 1
ZADD myzset 1 "uno"
(integer) 1
ZADD myzset 2 "two" 3 "three"
(integer) 2
ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
ZADD myzset 10 one 20 two 30 three
(integer) 0
ZRANGE myzset 0 -1 WITHSCORES
1) "uno"
2) "1"
3) "one"
4) "10"
5) "two"
6) "20"
7) "three"
8) "30"
ZADD myzset CH 100 one 200 two 300 three
(integer) 3
ZRANGE myzset 0 -1 WITHSCORES
1) "uno"
2) "1"
3) "one"
4) "100"
5) "two"
6) "200"
7) "three"
8) "300"
ZADD myzset XX 1 one 2 two 3 three 4 four 5 five
(integer) 0
ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
ZADD myzset NX 100 one 200 two 300 three 400 four 500 five
(integer) 2
ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
9) "four"
10) "400"
11) "five"
12) "500"
ZADD myzset INCR 10 one
"11"
ZRANGE myzset 0 -1 WITHSCORES
1) "uno"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "one"
8) "11"
9) "four"
10) "400"
11) "five"
12) "500"
ZADD myzset -inf "negative infinity" +inf "positive infinity"
(integer) 2
ZRANGE myzset 0 -1 WITHSCORES
1) "negative infinity"
2) "-inf"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
9) "one"
10) "11"
11) "four"
12) "400"
13) "five"
14) "500"
15) "positive infinity"
16) "inf"
1.1.2 ZCARD
ZCARD 命令用于获取有序集合中元素的数量。返回值为有序集合中元素的个数。
ZCARD key
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset
(integer) 2
1.1.3 ZCOUNT
ZCOUNT 命令用于返回分数在指定范围内(min 和 max)的元素个数。默认情况下,min 和 max 是包含边界的,可通过 ( 设置为排除边界。返回值为满足条件的元素个数。
ZCOUNT key min max
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZCOUNT myzset -inf +inf
(integer) 3
redis> ZCOUNT myzset 1 3
(integer) 3
redis> ZCOUNT myzset (1 3
(integer) 2
redis> ZCOUNT myzset (1 (3
(integer) 1
1.1.4 ZRANGE
ZRANGE 命令用于返回指定区间内的元素,按分数升序排列。通过添加 WITHSCORES 参数,可以同时返回元素及其分数。返回值为区间内的元素列表。
ZRANGE key start stop [WITHSCORES]
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
redis> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
redis> ZRANGE myzset 2 3
1) "three"
redis> ZRANGE myzset -2 -1
1) "two"
2) "three"
1.1.5 ZREVRANGE
ZREVRANGE 命令用于返回指定区间内的元素,按分数降序排列。通过添加 WITHSCORES 参数,可以同时返回元素及其分数。返回值为区间内的元素列表。
ZREVRANGE key start stop [WITHSCORES]
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREVRANGE myzset 0 -1 WITHSCORES
1) "three"
2) "3"
3) "two"
4) "2"
5) "one"
6) "1"
redis> ZREVRANGE myzset 0 -1
1) "three"
2) "two"
3) "one"
redis> ZREVRANGE myzset 2 3
1) "one"
redis> ZREVRANGE myzset -2 -1
1) "two"
2) "one"
1.1.6 ZRANGEBYSCORE
ZRANGEBYSCORE 命令用于返回分数在指定范围内(min 和 max)的元素。默认情况下,min 和 max 是包含边界的,可通过 ( 设置为排除边界。注意:此命令可能在 Redis 6.2.0 之后被废弃,其功能已合并到 ZRANGE 命令中。返回值为区间内的元素列表。
ZRANGEBYSCORE key min max [WITHSCORES]
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANGEBYSCORE myzset -inf +inf
1) "one"
2) "two"
3) "three"
redis> ZRANGEBYSCORE myzset 1 2
1) "one"
2) "two"
redis> ZRANGEBYSCORE myzset (1 2
1) "two"
redis> ZRANGEBYSCORE myzset (1 (2
(empty array)
1.1.7 ZPOPMAX
ZPOPMAX 命令用于删除并返回有序集合中分数最高的 count 个元素。返回值为包含元素及其分数的列表。
ZPOPMAX key [count]
ZADD myzset 1 "one"
(integer) 1
ZADD myzset 2 "two"
(integer) 1
ZADD myzset 3 "three"
(integer) 1
ZPOPMAX myzset
1) "three"
2) "3"
1.1.8 BZPOPMAX
BZPOPMAX 命令是 ZPOPMAX 的阻塞版本,用于删除并返回有序集合中分数最高的元素。返回值为包含元素及其分数的列表。
BZPOPMAX key [key ...] timeout
redis> DEL zset1 zset2
(integer) 0
redis> ZADD zset1 0 a 1 b 2 c
(integer) 3
redis> BZPOPMAX zset1 zset2 0
1) "zset1"
2) "c"
3) "2"
1.1.9 ZPOPMIN
ZPOPMIN 命令用于删除并返回有序集合中分数最低的 count 个元素。返回值为包含元素及其分数的列表。
ZPOPMIN key [count]
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZPOPMIN myzset
1) "one"
2) "1"
1.1.10 BZPOPMIN
BZPOPMIN 命令是 ZPOPMIN 的阻塞版本,用于删除并返回有序集合中分数最低的元素。返回值为包含元素及其分数的列表。
BZPOPMIN key [key ...] timeout
redis> DEL zset1 zset2
(integer) 0
redis> ZADD zset1 0 a 1 b 2 c
(integer) 3
redis> BZPOPMIN zset1 zset2 0
1) "zset1"
2) "a"
3) "0"
1.1.11 ZRANK
ZRANK 命令用于返回指定元素在有序集合中的排名(按分数升序排列)。返回值为该元素的排名。
ZRANK key member
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZRANK myzset "three"
(integer) 2
redis> ZRANK myzset "four"
(nil)
1.1.12 ZREVRANK
ZREVRANK 命令用于返回指定元素在有序集合中的排名(按分数降序排列)。返回值为该元素的排名。
ZREVRANK key member
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREVRANK myzset "one"
(integer) 2
redis> ZREVRANK myzset "four"
(nil)
1.1.13 ZSCORE
ZSCORE 命令用于获取指定元素在有序集合中的分数。返回值为该元素的分数。
ZSCORE key member
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZSCORE myzset "one"
"1"
1.1.14 ZREM
ZREM 命令用于删除有序集合中指定的元素。返回值为成功删除的元素个数。
ZREM key member [member ...]
ZADD myzset 1 "one"
(integer) 1
ZADD myzset 2 "two"
(integer) 1
ZADD myzset 3 "three"
(integer) 1
ZREM myzset "two"
(integer) 1
ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"
1.1.15 ZREMRANGEBYRANK
ZREMRANGEBYRANK 命令按分数升序排序,删除指定范围内的元素(左闭右闭)。返回值为成功删除的元素个数。
ZREMRANGEBYRANK key start stop
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREMRANGEBYRANK myzset 0 1
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "three"
2) "3"
1.1.16 ZREMRANGEBYSCORE
ZREMRANGEBYSCORE 命令用于删除分数在指定范围内的元素(左闭右闭)。返回值为成功删除的元素个数。
ZREMRANGEBYSCORE key min max
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREMRANGEBYSCORE myzset -inf (2
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "three"
4) "3"
1.1.17 ZINCRBY
ZINCRBY 命令用于为指定元素的分数增加指定的值。返回值为元素更新后的分数。
ZINCRBY key increment member
ZADD myzset 1 "one"
(integer) 1
ZADD myzset 2 "two"
(integer) 1
ZINCRBY myzset 2 "one"
"3"
ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "one"
4) "3"
1.1.18 集合间操作
1.1.19 ZINTERSTORE
ZINTERSTORE 命令用于计算指定有序集合的交集,并将结果存储到目标有序集合中。交集的分数通过指定的聚合方式和权重计算得出。返回值为目标集合中的元素个数。
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
redis> ZADD zset1 1 "one"
(integer) 1
redis> ZADD zset1 2 "two"
(integer) 1
redis> ZADD zset2 1 "one"
(integer) 1
redis> ZADD zset2 2 "two"
(integer) 1
redis> ZADD zset2 3 "three"
(integer) 1
redis> ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
(integer) 2
redis> ZRANGE out 0 -1 WITHSCORES
1) "one"
2) "5"
3) "two"
4) "10"
1.1.20 ZUNIONSTORE
ZUNIONSTORE 命令用于计算指定有序集合的并集,并将结果存储到目标有序集合中。并集的分数通过指定的聚合方式和权重计算得出。返回值为目标集合中的元素个数。
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
redis> ZADD zset1 1 "one"
(integer) 1
redis> ZADD zset1 2 "two"
(integer) 1
redis> ZADD zset2 1 "one"
(integer) 1
redis> ZADD zset2 2 "two"
(integer) 1
redis> ZADD zset2 3 "three"
(integer) 1
redis> ZUNIONSTORE out 2 zset1 zset2 WEIGHTS 2 3
(integer) 3
redis> ZRANGE out 0 -1 WITHSCORES
1) "one"
2) "5"
3) "three"
4) "9"
5) "two"
6) "10"
1.1.21 命令小结
命令 | 时间复杂度 | 描述 |
---|---|---|
zadd key score member [score member …] | O(k * log(n)),k 是添加成员的个数,n 是当前有序集合的元素个数 | 添加一个或多个成员到有序集合,并设置分数 |
zcard key | O(1) | 获取有序集合中的成员数量 |
zscore key member | O(1) | 获取指定成员的分数 |
zrank key member / zrevrank key member | O(log(n)),n 是当前有序集合的元素个数 | 获取指定成员的排名(升序或降序) |
zrem key member [member …] | O(k * log(n)),k 是删除成员的个数,n 是当前有序集合的元素个数 | 删除一个或多个指定成员 |
zincrby key increment member | O(log(n)),n 是当前有序集合的元素个数 | 增加指定成员的分数 |
zrange key start end [withscores] | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 获取指定区间内的成员,按分数升序排序 |
zrevrange key start end [withscores] | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 获取指定区间内的成员,按分数降序排序 |
zrangebyscore key min max [withscores] | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 获取指定分数范围内的成员,按分数升序排序 |
zrevrangebyscore key max min [withscores] | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 获取指定分数范围内的成员,按分数降序排序 |
zcount key min max | O(log(n)),n 是当前有序集合的元素个数 | 获取指定分数范围内的成员数量 |
zremrangebyrank key start end | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 删除指定排名范围内的成员 |
zremrangebyscore key min max | O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数 | 删除指定分数范围内的成员 |
zinterstore destination numkeys key [key…] | O(n * k) + O(m * log(m)),n 是输入集合最小的元素个数,k 是集合个数,m 是目标集合的元素个数 | 计算多个有序集合的交集并存储到目标有序集合 |
zunionstore destination numkeys key [key…] | O(n) + O(m * log(m)),n 是输入集合总元素个数,m 是目标集合的元素个数 | 计算多个有序集合的并集并存储到目标有序集合 |
1.2 内部编码
有序集合类型的内部编码有两种:
内部编码类型 | 使用条件 | 描述 |
---|---|---|
ziplist | 当有序集合的元素个数小于 zset-max-ziplist-entries(默认 128 个),且每个元素的值小于 zset-max-ziplist-value(默认 64 字节)时使用。 | 使用压缩列表结构,能够有效减少内存使用。 |
skiplist | 当不满足 ziplist 的条件时使用。 | 使用跳表结构,提供更高的操作效率。 |
- 当元素个数较少且每个元素较小时,内部编码为 ziplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
(integer) 3
127.0.0.1:6379> object encoding zsetkey
"ziplist"
- 当元素个数超过 128 个,内部编码 skiplist:
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 ... 省略 ... 82 e129
(integer) 129
127.0.0.1:6379> object encoding zsetkey
"skiplist"
- 当某个元素大于 64 字节时,内部编码 skiplist:
127.0.0.1:6379> zadd zsetkey 50 "one string bigger than 64 bytes ... 省略 ..."
(integer) 1
127.0.0.1:6379> object encoding zsetkey
"skiplist"
1.3 使用场景
有序集合的典型应用场景是排行榜系统,例如网站上的热门榜单信息。榜单可以基于多种维度进行排序,例如时间、阅读量或点赞量。在本例中,我们以点赞数为维度,来维护每天的热榜。
- 添加用户赞数
例如用户 james 发布了⼀篇文章,并获得 3 个赞,可以使用有序集合的 zadd 和 zincrby 功能:
zadd user:ranking:2022-03-15 3 james
之后如果再获得赞,可以使⽤ zincrby:
zincrby user:ranking:2022-03-15 1 james
- 取消用户赞数
zrem user:ranking:2022-03-15 tom
- 展示获取赞数最多的 10 个用户
zrevrangebyrank user:ranking:2022-03-15 0 9
- 展示用户信息以及用户分数
hgetall user:info:tom
zscore user:ranking:2022-03-15 mike
zrank user:ranking:2022-03-15 mike