Redis-Zest

Zest有序集合

zest集合不能有重复成员特点,与集合不同的是,有序集合的每一个元素都有唯一一个浮点类型的分数跟value关联。有序集合的元素不能重复,但是关联的分数可以重复。

zset命令

zadd命令

添加或者更新指定元素以及关联的分数到zest中

ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]

  • XX: 仅用于更新已经存在的元素,不会添加新元素。

  • NX: 仅用于添加新元素,不会更新已经存在的元素。

  • LT:只更新已经存在的元素,如果新的分数比当前的分数小,成功,否则不更新

  • GT:只更新已经存在的元素,如果新的分数比当前的分数大,成功,否则不更新

  • CH: 默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。

  • INCR: 此时命令会类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定一个元素和分数。

不添加NX和XX选项时,就会有同时有两个效果,member不存在时,会添加新的member进来,如果存在就会更新member的值。

Redis 的实际行为是:​​忽略无效的 IX选项​ ​,并将命令解析为普通的 ZADD更新操作。也就是说,它会更新已存在成员的分数(如果成员存在),或添加新成员(如果成员不存在)。

bash 复制代码
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 1 "uno"
(integer) 0
redis> ZADD myzset 2 "two" 3 "three"
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
redis> ZADD myzset 10 one 20 two 30 three
(integer) 0
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "10"
3) "two"
4) "20"
5) "three"
6) "30"
redis> ZADD myzset IX 100 one 200 two 300 three
(integer) 3
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "100"
3) "two"
4) "200"
5) "three"
6) "300"
redis> ZADD myzset XX 1 one 2 two 3 three 4 four 5 five
(integer) 0
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "4"
9) "five"
10) "5"
redis> ZADD myzset -inf "negative infinity" +inf "positive infinity"
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "negative infinity"
2) "-inf"
3) "uno"
4) "1"
5) "one"
6) "2"
7) "two"
8) "20"
9) "three"
10) "30"
11) "four"
12) "4"
13) "five"
14) "5"
15) "positive infinity"
16) "inf"

zcard命令

获取一个zest的基数,也就是zest的元素个数

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZADD myzset 2 "two"

(integer) 1

redis> ZCARD myzset

(integer) 2

zsocre命令

返回指定元素的分数

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZSCORE myzset "one"

"1"

zrank命令

按照元素的排名,升序形式

bash 复制代码
> ZADD leaderboard 1500 "player1" 2000 "player2" 1800 "player3" 1700 "player4"
(integer) 4

> ZRANK leaderboard "player3"
(integer) 2    # player3在排行榜中是第三名

> ZREVRANK leaderboard "player3"
(integer) 1    # 从高到低排序时,player3是第二名

zrevrank命令

按照元素排名,降序形式,与zrank相反的结果

zrem命令

删除指定元素

bash 复制代码
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREM myzset "two"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"

zincrby命令

指定元素对其关联的分数进行添加一个值

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZADD myzset 2 "two"

(integer) 1

redis> ZINCRBY myzset 2 "one"

"3"

redis> ZRANGE myzset 0 -1 WITHSCORES

  1. "two"

  2. "2"

  3. "one"

  4. "3"

zrange命令

返回指定区间里的元素,分数按照升序,带上WITHSCORES可以把分数也返回

bash 复制代码
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) "two"
2) "three"
redis> ZRANGE myzset -2 -1
1) "two"
2) "three"

zrevrange命令

跟zrange命令相反,这里是按照降序

bash 复制代码
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 -1
1) "two"
2) "one"

zrangebyscore命令

返回分数在min和max之间的元素,max和min默认是闭合的

bash 复制代码
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)

zpopmax命令(zpopmin)

删除并返回分数最高的count个元素,若是有多个分数相同,则就按照字典值最大的返回(strcmp)

redis> ZADD myzset 1 "one"

(integer) 1

redis> ZADD myzset 2 "two"

(integer) 1

redis> ZADD myzset 3 "three"

(integer) 1

redis> ZPOPMAX myzset

  1. "three"

  2. "3"

bzpopmax命令(bzpopmin)

zpopmax的阻塞版本

1. 正确添加数据

DEL zset1

ZADD zset1 10 "apple" 20 "banana" 30 "cherry"

2. 阻塞弹出(立即返回,因有数据)

BZPOPMAX zset1 0

返回:1) "zset1" 2) "cherry" 3) "30"

3. 空集合阻塞示例(需另开客户端插入数据测试)

DEL zset2

BZPOPMAX zset2 5 # 最多等待5秒

超时返回:(nil)

zcount命令

返回的分数在min和max之间的元素个数,min和max都是包含的,而要排除边界就要 (

命令示例 数学表示 匹配分数范围 匹配结果
ZCOUNT myzset 1 3 [1, 3] 1 ≤ x ≤ 3 one, two, three
ZCOUNT myzset (1 3 (1, 3) 1 < x < 3 two
ZCOUNT myzset 1 (3 [1, 3) 1 ≤ x < 3 one, two
ZCOUNT myzset (1 (3 (1, 3) 1 < x < 3 two

zremrangebyrank命令

按照排名以升序形式删除指定范围的元素,左闭有闭,rank是下标,以下标范围来指定范围

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"

zremrangebyscore命令

与zremrangebyrank不同,以分数来指定范围

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"

zinterstore命令

选中集合求集合元素的交集并保存到一个有序集合中

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]

estination: 目标有序集合的名称。

numkeys: 输入有序集合的数量。

key: 输入有序集合的名称。

WEIGHTS weight \[weight ...\]\]: 为每个输入有序集合指定一个权重。 \[AGGREGATE \\]: 指定分数聚合方式。 这里需要numkeys的理由就像http协议需要在报头位置提供这个报文的总大小 ```bash -- 清除可能存在的旧数据 DEL zset1 zset2 result1 result2 result3 result4 result5 -- 创建两个有序集合作为测试数据 ZADD zset1 10 "apple" 20 "banana" 30 "cherry" ZADD zset2 15 "banana" 25 "cherry" 35 "date" -- 查看原始数据 ECHO "==== 原始数据 ====" ECHO "zset1:" ZRANGE zset1 0 -1 WITHSCORES ECHO "zset2:" ZRANGE zset2 0 -1 WITHSCORES -- 示例1:基本交集运算(默认SUM聚合) ECHO "\n==== 示例1:基本交集(SUM)====" ZINTERSTORE result1 2 zset1 zset2 ZRANGE result1 0 -1 WITHSCORES -- 示例2:带权重的交集(zset1×2,zset2×3) ECHO "\n==== 示例2:带权重(2和3)====" ZINTERSTORE result2 2 zset1 zset2 WEIGHTS 2 3 ZRANGE result2 0 -1 WITHSCORES -- 示例3:MIN聚合方式(取较小值) ECHO "\n==== 示例3:MIN聚合 ====" ZINTERSTORE result3 2 zset1 zset2 AGGREGATE MIN ZRANGE result3 0 -1 WITHSCORES -- 示例4:MAX聚合方式(取较大值) ECHO "\n==== 示例4:MAX聚合 ====" ZINTERSTORE result4 2 zset1 zset2 AGGREGATE MAX ZRANGE result4 0 -1 WITHSCORES -- 示例5:权重+MAX聚合组合 ECHO "\n==== 示例5:权重(1,2)+MAX ====" ZINTERSTORE result5 2 zset1 zset2 WEIGHTS 1 2 AGGREGATE MAX ZRANGE result5 0 -1 WITHSCORES ``` **结果** ```bash ==== 原始数据 ==== zset1: 1) "apple" 2) "10" 3) "banana" 4) "20" 5) "cherry" 6) "30" zset2: 1) "banana" 2) "15" 3) "cherry" 4) "25" 5) "date" 6) "35" ==== 示例1:基本交集(SUM)==== 1) "banana" 2) "35" 3) "cherry" 4) "55" ==== 示例2:带权重(2和3)==== 1) "banana" 2) "85" 3) "cherry" 4) "135" ==== 示例3:MIN聚合 ==== 1) "banana" 2) "15" 3) "cherry" 4) "25" ==== 示例4:MAX聚合 ==== 1) "banana" 2) "20" 3) "cherry" 4) "30" ==== 示例5:权重(1,2)+MAX ==== 1) "banana" 2) "30" 3) "cherry" 4) "50" ``` **zunionstore命令** 选中的集合以合集形式存储在新的有序集合中 > ZUNIONSTORE destination numkeys key \[key ...\] \[WEIGHTS weight \[weight ...\]\] \[AGGREGATE \

estination: 目标有序集合的名称。

numkeys: 输入有序集合的数量。需要有这个字段是因为 numkeys 描述出 key 的个数之后,就可以明确的知道,后面的"选项"是从哪里开始的,避免选项和 keys 混淆!

key: 输入有序集合的名称。

WEIGHTS weight \[weight ...\]\]: 为每个输入有序集合指定一个权重。 \[AGGREGATE \\]: 指定分数聚合方式。 ```bash -- 清除可能存在的旧数据 DEL zset1 zset2 result1 result2 result3 result4 result5 -- 创建两个有序集合作为测试数据 ZADD zset1 10 "apple" 20 "banana" 30 "cherry" ZADD zset2 15 "banana" 25 "cherry" 35 "date" -- 查看原始数据 ECHO "==== 原始数据 ====" ECHO "zset1:" ZRANGE zset1 0 -1 WITHSCORES ECHO "zset2:" ZRANGE zset2 0 -1 WITHSCORES -- 示例1:基本并集运算(默认SUM聚合) ECHO "\n==== 示例1:基本并集(SUM)====" ZUNIONSTORE result1 2 zset1 zset2 ZRANGE result1 0 -1 WITHSCORES -- 示例2:带权重的并集(zset1×2,zset2×3) ECHO "\n==== 示例2:带权重(2和3)====" ZUNIONSTORE result2 2 zset1 zset2 WEIGHTS 2 3 ZRANGE result2 0 -1 WITHSCORES -- 示例3:MIN聚合方式(取较小值) ECHO "\n==== 示例3:MIN聚合 ====" ZUNIONSTORE result3 2 zset1 zset2 AGGREGATE MIN ZRANGE result3 0 -1 WITHSCORES -- 示例4:MAX聚合方式(取较大值) ECHO "\n==== 示例4:MAX聚合 ====" ZUNIONSTORE result4 2 zset1 zset2 AGGREGATE MAX ZRANGE result4 0 -1 WITHSCORES -- 示例5:权重+MAX聚合组合 ECHO "\n==== 示例5:权重(1,2)+MAX ====" ZUNIONSTORE result5 2 zset1 zset2 WEIGHTS 1 2 AGGREGATE MAX ZRANGE result5 0 -1 WITHSCORES ``` **结果** ```bash ==== 原始数据 ==== zset1: 1) "apple" 2) "10" 3) "banana" 4) "20" 5) "cherry" 6) "30" zset2: 1) "banana" 2) "15" 3) "cherry" 4) "25" 5) "date" 6) "35" ==== 示例1:基本并集(SUM)==== 1) "apple" 2) "10" 3) "date" 4) "35" 5) "banana" 6) "35" 7) "cherry" 8) "55" ==== 示例2:带权重(2和3)==== 1) "apple" 2) "20" 3) "date" 4) "105" 5) "banana" 6) "85" 7) "cherry" 8) "135" ==== 示例3:MIN聚合 ==== 1) "apple" 2) "10" 3) "date" 4) "35" 5) "banana" 6) "15" 7) "cherry" 8) "25" ==== 示例4:MAX聚合 ==== 1) "apple" 2) "10" 3) "date" 4) "35" 5) "banana" 6) "20" 7) "cherry" 8) "30" ==== 示例5:权重(1,2)+MAX ==== 1) "apple" 2) "10" 3) "date" 4) "70" 5) "banana" 6) "30" 7) "cherry" 8) "50" ``` ![](https://i-blog.csdnimg.cn/direct/a4810b673bdf451eb07509180e1eb0e6.png) ## **命令总结** ![](https://i-blog.csdnimg.cn/direct/371af2d927fb4c13918650f78cad81e4.png) ## 内部编码 **1.ziplist压缩列表**: 当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都小于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会用 ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。 **2.skiplist跳表**: 当 ziplist 条件不满足时,有序集合会使用 skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降。 ![](https://i-blog.csdnimg.cn/direct/dc3814a9a85341a4b2339f4aea3b3387.png) ## 使用场景 1. **排行榜系统** * **微博热搜** * 根据话题的热度(如浏览量、点赞量、转发量、评论量等)进行排行,热度是实时变化的,需要高效更新排行。 * 热度是一个综合数值,由多个维度加权计算得出。 * **游戏天梯排行** * 根据玩家的天梯积分进行排序,玩家的分数会随着游戏结果实时变化,需要及时更新排名。 * 排名可能会影响匹配机制。 * **成绩排行** * 适用于各种需要根据分数进行排名的场景,如考试成绩、比赛成绩等。 2. **其他需要动态排序的场景** * 只要需要利用 ZSet 的有序特性,都可以考虑使用 ZSet 或类似的有序集合数据结构。 ##### ZSet 的优势 * **高效更新** * ZSet 能够在 **O(log n)** 的时间复杂度内更新分数和排名,适合实时变化的场景。 * **方便查询** * 可以通过分数范围或排名范围进行快速查询,操作简单且高效。 ##### 存储空间分析 * **存储需求** * 假设每个玩家信息(如用户 ID)占用 4 字节,分数(如天梯积分)占用 8 字节,每个玩家总共需要 12 字节。 * 对于 1 亿玩家,存储空间需求为: 1亿×12字节=1.2GB * 即使对于 10 亿玩家,存储空间也仅为 12GB,现代服务器和家用电脑都能轻松应对。 * **数据量级理解** * 学会快速估算数据量级,如 **thousand(千)对应 KB,million(百万)对应 MB,billion(十亿)对应 GB**。 * 这种估算能力对于评估系统需求和优化性能非常重要。 ##### 复杂排行榜的实现 * **微博热度计算** * 热度是一个综合数值,由多个维度(如浏览量、点赞量、转发量、评论量等)加权计算得出。 * 权重分配通常由专业团队通过人工智能和数据模型进行优化。 * **ZSet 的加权操作** * 可以使用 **ZINTERSTORE** 或 **ZUNIONSTORE** 命令,为每个维度的有序集合分配权重,计算出综合热度。 * 例如,将浏览量、点赞量、转发量、评论量分别存储在不同的有序集合中,然后通过加权并集或交集操作得到最终的热度排行。 ##### 学习 ZSet 的意义 * **启发和参考** * 学习 ZSet 不仅是为了直接使用 Redis,更是为了理解其背后的机制和原理。 * 这些原理可以应用于其他场景,如使用其他语言库实现有序集合,或者自己实现类似的数据结构。 * **知识迁移** * 学习任何技术或原理的目的是为了在不同场景中灵活应用,如操作系统、网络、数据库等领域的知识,都能为解决问题提供思路。

相关推荐
zl9798995 小时前
Redis-stream、bitfield类型
数据库·redis·缓存
数据库那些事儿5 小时前
Qoder + ADB Supabase :5分钟GET超火AI手办生图APP
数据库·后端
IvorySQL5 小时前
PostgreSQL 18 异步 I/O(AIO)调优指南
数据库·postgresql
kakacc:5 小时前
记录一次巧妙的SQL:一对多关联导致的 sum () 、count()等group函数重复计算问题
数据库·sql
心随雨下5 小时前
Redis中Geospatial 实际应用指南
数据库·redis·分布式·缓存
黑夜管理员5 小时前
Sql Server安装报错“服务没有及时响应启动或控制请求”
数据库·sql server
NineData6 小时前
NineData云原生智能数据管理平台新功能发布|2025年9月版
数据库·云原生·devops·ninedata·数据库迁移·数据复制·风险sql管控
junnhwan6 小时前
【苍穹外卖笔记】Day04--套餐管理模块
java·数据库·spring boot·后端·苍穹外卖·crud
月临水7 小时前
Redis 学习笔记(二)
redis·笔记·学习