Redis 有序集合(下)
本课学习有序集合的按分数范围查询、集合运算等高级功能。
ZRANGEBYSCORE:按分数范围查询
ZRANGEBYSCORE根据分数范围获取元素。
基本用法
REDIS
ZADD leaderboard 100 "player1" 150 "player2" 200 "player3" 250 "player4" 300 "player5"
# 获取分数在150到250之间的元素
ZRANGEBYSCORE leaderboard 150 250
1) "player2"
2) "player3"
3) "player4"
# 获取元素和分数
ZRANGEBYSCORE leaderboard 150 250 WITHSCORES
1) "player2"
2) "150"
3) "player3"
4) "200"
5) "player4"
6) "250"
使用-inf和+inf
REDIS
# 获取分数小于等于200的元素
ZRANGEBYSCORE leaderboard -inf 200
1) "player1"
2) "player2"
3) "player3"
# 获取分数大于等于200的元素
ZRANGEBYSCORE leaderboard 200 +inf
1) "player3"
2) "player4"
3) "player5"
# 获取所有元素
ZRANGEBYSCORE leaderboard -inf +inf
开区间和闭区间
REDIS
# 默认是闭区间 [150, 250]
ZRANGEBYSCORE leaderboard 150 250
# 开区间 (150, 250) - 不包含150和250
ZRANGEBYSCORE leaderboard (150 (250
# 半开区间 [150, 250)
ZRANGEBYSCORE leaderboard 150 (250
# 半开区间 (150, 250]
ZRANGEBYSCORE leaderboard (150 250
💡 语法: 使用括号
( 表示开区间(不包含),不使用括号表示闭区间(包含)。
LIMIT分页
REDIS
# 获取分数在100到300之间的元素,从第1个开始,取2个
ZRANGEBYSCORE leaderboard 100 300 LIMIT 1 2
1) "player2"
2) "player3"
ZREVRANGEBYSCORE:按分数范围查询(从高到低)
REDIS
# 从高到低获取分数在150到250之间的元素
ZREVRANGEBYSCORE leaderboard 250 150 WITHSCORES
1) "player4"
2) "250"
3) "player3"
4) "200"
5) "player2"
6) "150"
⚠️ 注意: ZREVRANGEBYSCORE的分数范围要从大到小写(250 150),而不是从小到大。
ZRANGEBYLEX:按元素字典序查询
当所有元素分数相同时,可以按字典序查询。
基本用法
REDIS
# 所有元素分数为0
ZADD myzset 0 "apple" 0 "banana" 0 "cherry" 0 "date"
# 按字典序获取所有元素
ZRANGEBYLEX myzset - +
1) "apple"
2) "banana"
3) "cherry"
4) "date"
# 获取字典序在[banana, cherry]之间的元素
ZRANGEBYLEX myzset [banana [cherry
1) "banana"
2) "cherry"
# 获取以b开头的元素
ZRANGEBYLEX myzset [b (c
1) "banana"
💡 用途: ZRANGEBYLEX适合实现自动补全、字典查询等功能。
ZREMRANGEBYRANK:按排名范围删除
REDIS
ZADD leaderboard 100 "p1" 150 "p2" 200 "p3" 250 "p4" 300 "p5"
# 删除排名0到1的元素(分数最低的2个)
ZREMRANGEBYRANK leaderboard 0 1
(integer) 2
ZRANGE leaderboard 0 -1
1) "p3"
2) "p4"
3) "p5"
ZREMRANGEBYSCORE:按分数范围删除
REDIS
ZADD leaderboard 100 "p1" 150 "p2" 200 "p3" 250 "p4" 300 "p5"
# 删除分数在100到200之间的元素
ZREMRANGEBYSCORE leaderboard 100 200
(integer) 3
ZRANGE leaderboard 0 -1 WITHSCORES
1) "p4"
2) "250"
3) "p5"
4) "300"
应用:清理过期数据
REDIS
# 延迟队列(分数为时间戳)
ZADD delay:queue 1719129600 "task:1"
ZADD delay:queue 1719133200 "task:2"
# 删除已执行的任务(时间戳小于当前时间)
ZREMRANGEBYSCORE delay:queue -inf 1719129600
ZREMRANGEBYLEX:按字典序范围删除
REDIS
ZADD myzset 0 "apple" 0 "banana" 0 "cherry" 0 "date"
# 删除字典序在[banana, cherry]之间的元素
ZREMRANGEBYLEX myzset [banana [cherry
(integer) 2
ZRANGE myzset 0 -1
1) "apple"
2) "date"
有序集合运算
ZUNIONSTORE:并集
REDIS
# 创建两个有序集合
ZADD zset1 1 "a" 2 "b" 3 "c"
ZADD zset2 4 "b" 5 "c" 6 "d"
# 计算并集(默认求和)
ZUNIONSTORE result 2 zset1 zset2
(integer) 4
ZRANGE result 0 -1 WITHSCORES
1) "a"
2) "1"
3) "d"
4) "6"
5) "b"
6) "6" # 2 + 4
7) "c"
8) "8" # 3 + 5
ZUNIONSTORE权重
REDIS
# 设置权重
ZUNIONSTORE result 2 zset1 zset2 WEIGHTS 2 3
# zset1的分数乘以2,zset2的分数乘以3
ZRANGE result 0 -1 WITHSCORES
1) "a"
2) "2" # 1 * 2
3) "d"
4) "18" # 6 * 3
5) "b"
6) "16" # 2*2 + 4*3
7) "c"
8) "21" # 3*2 + 5*3
ZUNIONSTORE聚合函数
REDIS
# 使用MIN聚合(取最小分数)
ZUNIONSTORE result 2 zset1 zset2 AGGREGATE MIN
# 使用MAX聚合(取最大分数)
ZUNIONSTORE result 2 zset1 zset2 AGGREGATE MAX
# 使用SUM聚合(求和,默认)
ZUNIONSTORE result 2 zset1 zset2 AGGREGATE SUM
ZINTERSTORE:交集
REDIS
ZADD zset1 1 "a" 2 "b" 3 "c"
ZADD zset2 4 "b" 5 "c" 6 "d"
# 计算交集
ZINTERSTORE result 2 zset1 zset2
(integer) 2
ZRANGE result 0 -1 WITHSCORES
1) "b"
2) "6" # 2 + 4
3) "c"
4) "8" # 3 + 5
ZDIFFSTORE:差集(Redis 6.2+)
REDIS
ZADD zset1 1 "a" 2 "b" 3 "c"
ZADD zset2 4 "b" 5 "c" 6 "d"
# 计算差集
ZDIFFSTORE result 2 zset1 zset2
(integer) 1
ZRANGE result 0 -1 WITHSCORES
1) "a"
2) "1"
ZMSCORE:批量获取分数(Redis 6.2+)
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
ZMSCORE leaderboard "player1" "player2" "player4"
1) "100"
2) "200"
3) (nil) # player4不存在
ZPOPMAX和ZPOPMIN:弹出分数最高/最低的元素
ZPOPMAX:弹出分数最高的元素
REDIS
ZADD leaderboard 100 "p1" 200 "p2" 300 "p3"
# 弹出分数最高的元素
ZPOPMAX leaderboard
1) "p3"
2) "300"
# 弹出分数最高的2个元素
ZPOPMAX leaderboard 2
1) "p2"
2) "200"
3) "p1"
4) "100"
ZPOPMIN:弹出分数最低的元素
REDIS
ZADD leaderboard 100 "p1" 200 "p2" 300 "p3"
ZPOPMIN leaderboard
1) "p1"
2) "100"
BZPOPMAX和BZPOPMIN:阻塞式弹出
REDIS
# 如果有序集合为空,阻塞等待最多10秒
BZPOPMAX leaderboard 10
# 同时监听多个有序集合
BZPOPMAX zset1 zset2 zset3 10
💡 用途: BZPOPMAX/BZPOPMIN可用于实现优先级队列。
有序集合高级应用
场景1:滑动窗口限流
REDIS
# 记录用户请求时间戳
ZADD ratelimit:user:1 1719129600 "req1"
ZADD ratelimit:user:1 1719129605 "req2"
ZADD ratelimit:user:1 1719129610 "req3"
# 获取最近60秒内的请求数量
ZCOUNT ratelimit:user:1 1719129540 1719129600
# 清理60秒前的请求
ZREMRANGEBYSCORE ratelimit:user:1 -inf 1719129540
场景2:自动补全
REDIS
# 所有单词分数为0
ZADD autocomplete 0 "apple" 0 "application" 0 "appetite" 0 "banana"
# 查询以"app"开头的单词
ZRANGEBYLEX autocomplete [app [app\xff
1) "apple"
2) "application"
3) "appetite"
场景3:时间线
REDIS
# 用户时间线(分数为时间戳)
ZADD timeline:user:1 1719129600 "post:1"
ZADD timeline:user:1 1719129605 "post:2"
ZADD timeline:user:1 1719129610 "post:3"
# 获取最新的10条动态
ZREVRANGE timeline:user:1 0 9
# 获取某个时间段的动态
ZRANGEBYSCORE timeline:user:1 1719129600 1719129610
场景4:多维度排序
REDIS
# 商品销量排序
ZADD sales:rank 1000 "product:1"
ZADD sales:rank 2000 "product:2"
# 商品评分排序
ZADD rating:rank 4.5 "product:1"
ZADD rating:rank 4.8 "product:2"
# 综合排序(销量权重0.6,评分权重0.4)
ZUNIONSTORE combined:rank 2 sales:rank rating:rank WEIGHTS 0.6 0.4
❓ 常见问题
Q ZRANGEBYSCORE和ZRANGE的区别?
A ZRANGE按排名范围查询,ZRANGEBYSCORE按分数范围查询。
Q 如何获取分数最高的N个元素?
A 使用ZREVRANGE key 0 N-1 WITHSCORES。
Q ZUNIONSTORE的权重如何理解?
A 权重是乘法因子。WEIGHTS 2 3表示第一个集合分数乘以2,第二个集合分数乘以3。
Q ZRANGEBYLEX要求所有元素分数相同吗?
A 是的。ZRANGEBYLEX假设所有元素分数相同,按字典序排序。
Q 如何实现优先级队列?
A 使用ZADD添加任务(分数为优先级),使用ZPOPMIN取出优先级最高的任务。
📖 小节
- ZRANGEBYSCORE按分数范围查询,支持开区间和LIMIT
- ZRANGEBYLEX按字典序查询(所有元素分数相同)
- ZREMRANGEBYRANK/SCORE/LEX按范围删除元素
- ZUNIONSTORE/ZINTERSTORE集合运算,支持权重和聚合函数
- ZPOPMAX/ZPOPMIN弹出分数最高/最低的元素
- BZPOPMAX/BZPOPMIN阻塞式弹出,用于优先级队列
- 高级应用:滑动窗口限流、自动补全、时间线、多维度排序
📝 作业
- 分数范围查询: 使用ZRANGEBYSCORE查询不同分数范围的元素
- 范围删除: 使用ZREMRANGEBYSCORE删除过期数据
- 集合运算: 使用ZUNIONSTORE合并多个排行榜,设置不同权重
- 滑动窗口: 使用有序集合实现滑动窗口限流
下一课
下一课我们将学习 Redis HyperLogLog,学习基数统计。



