Redis 常见数据类型-Zset 类型

Redis 常见数据类型-Zset 类型

七月 10, 2025 次阅读

类型简介

有序集合保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关联,这使得有序集合中的元素是可以维护有序性的,但这个有序不是用下标作为排序依据而是用这个分数。

下面是列表、集合、有序集合三者的异同点

数据结构 是否允许重复元素 是否有序 有序依据 应用场景
列表 索引下标 时间轴、消息队列等
集合 - 标签、社交等
有序集合 分数 排行榜系统、社交等

相关指令

ZADD 指令深度解析

将一个或多个成员元素及其分数值加入到有序集(sorted set)中。如果成员已经存在于有序集合中,则会更新其分数值,并根据新的分数值重新排序。

命令格式:

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

选项说明

  • NX:仅添加新元素,不更新已存在的元素
  • XX:仅更新已存在的元素,不添加新元素
  • GT:只有当新分数大于当前分数时才更新(Redis 7.0+)
  • LT:只有当新分数小于当前分数时才更新(Redis 7.0+)
  • CH:返回被修改的元素总数(包括新增和更新的)
  • INCR:将指定成员的分数增加给定值(相当于ZINCRBY)

时间复杂度:

  • O(log(N)):添加单个元素(N是有序集的基数)
  • O(M*log(N)):添加M个元素

返回值:

  • 不使用CH选项时:新增的元素数量
  • 使用CH选项时:被修改的元素总数(包括新增和更新的)
  • 使用INCR选项时:成员的新分数值(字符串形式)

使用示例

  1. 基本用法:
# 添加三个成员
127.0.0.1:6379> zadd myzset 1 "one" 2 "two" 3 "three"
(integer) 3

# 查看有序集
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
  1. 使用NX选项(仅添加新元素):
# 尝试更新已存在的元素"one"(失败)
127.0.0.1:6379> zadd myzset NX 4 "one" 5 "four"
(integer) 1  # 只新增了"four"

# 查看结果
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "5"
  1. 使用XX选项(仅更新已存在元素):
# 尝试更新已存在的"one"和新增"five"
127.0.0.1:6379> zadd myzset XX 10 "one" 5 "five"
(integer) 1  # 只更新了"one"

# 查看结果
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"
5) "four"
6) "5"
7) "one"
8) "10"  # "one"的分数被更新
  1. 使用CH选项(返回修改总数):
# 更新一个已存在元素,添加一个新元素
127.0.0.1:6379> zadd myzset CH 15 "one" 20 "five"
(integer) 2  # 一个更新,一个新增

# 查看结果
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"
5) "four"
6) "5"
7) "one"
8) "15"
9) "five"
10) "20"
  1. 使用INCR选项(分数递增):
# 将"one"的分数增加5
127.0.0.1:6379> zadd myzset INCR 5 "one"
"20"  # 返回新分数

# 查看结果
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"
5) "four"
6) "5"
7) "five"
8) "20"
9) "one"
10) "20"
  1. 使用GT/LT选项:
# 只有当新分数大于当前分数时才更新
127.0.0.1:6379> zadd myzset GT 25 "one"  # 当前分数20 < 25,会更新
(integer) 0

# 尝试用更小的分数更新
127.0.0.1:6379> zadd myzset GT 10 "one"  # 当前分数25 > 10,不会更新
(integer) 0

# 使用LT选项(只有当新分数小于当前分数时才更新)
127.0.0.1:6379> zadd myzset LT 8 "two"  # 当前分数2 < 8,不会更新
(integer) 0
127.0.0.1:6379> zadd myzset LT 1 "two"  # 当前分数2 > 1,会更新
(integer) 0

注意事项

  1. 分数值是64位双精度浮点数,可以表示的范围为-(2^53)到+(2^53)
  2. 相同分数的成员按字典序排序
  3. 从Redis 3.0.2开始,ZADD支持多参数语法
  4. GT/LT选项需要Redis 7.0及以上版本
  5. INCR选项不能与其他选项(NX/XX/GT/LT)一起使用

zcard

该指令获取—个 zset 的基数(cardinality),即 zset 中的元素个数

命令格式:

ZCARD key

时间复杂度:O(1)

返回值:zset 内的元素个数

使用示例:

127.0.0.1:6379> zadd k1 10 a 20 b
(integer) 2
# 查询 k1 中的元素个数
127.0.0.1:6379> zcard k1
(integer) 2

zcount

命令格式:

ZCOUNT key min max

返回有序集合中分数值在minmax之间的成员数量(默认包含边界值)

时间复杂度:O(log(N)),其中N是有序集合的基数

返回值:指定分数范围内的成员数量

开区间功能

  • 使用(前缀表示排除边界值(开区间)
  • (min表示大于min(不包含min)
  • (max表示小于max(不包含max)
  • 可以组合使用,如(min (max表示大于min且小于max

使用示例

  1. 基本用法(闭区间):
# 创建有序集合
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie" 400 "David"
(integer) 4

# 统计200-400分(包含边界)的成员
127.0.0.1:6379> ZCOUNT scores 200 400
(integer) 3  # 包含Bob(200), Charlie(300), David(400)
  1. 开区间用法:
# 统计大于200且小于400的成员(排除边界)
127.0.0.1:6379> ZCOUNT scores (200 (400
(integer) 1  # 仅Charlie(300)

# 仅排除下限
127.0.0.1:6379> ZCOUNT scores (200 400
(integer) 2  # Charlie(300), David(400)

# 仅排除上限
127.0.0.1:6379> ZCOUNT scores 200 (400
(integer) 2  # Bob(200), Charlie(300)
  1. 无限区间:
# 统计所有小于300分的成员
127.0.0.1:6379> ZCOUNT scores -inf 300
(integer) 3  # Alice(100), Bob(200), Charlie(300)

# 统计所有大于200分的成员(不包含200)
127.0.0.1:6379> ZCOUNT scores (200 +inf
(integer) 2  # Charlie(300), David(400)

注意事项

  1. 默认范围是闭区间(包含边界值)
  2. -inf+inf表示无限小和无限大
  3. 键不存在时返回0
  4. 分数值使用双精度浮点数存储

zrange

命令格式:

ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]

返回有序集合中指定区间内的成员,支持按索引、分数或字典序查询

核心功能

  1. 索引范围查询(默认):
    • startstop为从0开始的索引(包含边界)
    • 支持负数索引(-1表示最后一个元素)
# 获取前3个元素
127.0.0.1:6379> ZRANGE scores 0 2
1) "Alice"
2) "Bob"
3) "Charlie"
  1. 分数范围查询(BYSCORE):
    • 使用(表示开区间
    • 支持-inf+inf表示无限
# 获取分数在(100,300]之间的元素
127.0.0.1:6379> ZRANGE scores (100 300 BYSCORE
1) "Bob"
2) "Charlie"
  1. 字典序查询(BYLEX):
    • 要求所有元素分数相同
    • 使用[(指定闭/开区间
127.0.0.1:6379> ZADD k1 1 a 1 b 1 c 1 d 1 e 1 f
(integer) 6
# 获取字典序在[a,e)之间的元素
127.0.0.1:6379> ZRANGE k1 [a (e BYLEX
1) "a"
2) "b"
3) "c"
4) "d"

关键选项:

  • REV:反向排序(从高到低)
  • LIMIT:分页查询(类似SQL的LIMIT)
  • WITHSCORES:返回成员及其分数

时间复杂度:

  • O(log(N)+M),N是有序集合基数,M是返回元素数

使用示例:

  1. 基本范围查询:
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie"
(integer) 3
127.0.0.1:6379> ZRANGE scores 0 -1
1) "Alice"
2) "Bob"
3) "Charlie"
  1. 带分数的反向查询:
127.0.0.1:6379> ZRANGE scores 0 -1 REV WITHSCORES
1) "Charlie"
2) "300"
3) "Bob"
4) "200"
5) "Alice"
6) "100"
  1. 开区间查询:
127.0.0.1:6379> ZRANGE scores (100 (300 BYSCORE
1) "Bob"

注意事项

  1. Redis 6.2+版本开始替代了ZREVRANGE等命令
  2. 使用BYLEX时所有成员分数必须相同
  3. 大范围查询可能影响性能(时间复杂度O(log(N)+M))

ZREVRANGE

命令格式:

ZREVRANGE key start stop [WITHSCORES]

返回有序集合中指定索引范围内的成员,按分数从高到低排序(与ZRANGE排序相反)

核心特性

  1. 反向排序:默认按分数降序排列(最高分在前)
  2. 索引范围
    • startstop为基于0的索引
    • 支持负数索引(-1表示最后一个元素)
  3. 分数相同时按字典序降序排列

时间复杂度:O(log(N)+M),N是有序集合基数,M是返回元素数

返回值:指定范围内的成员列表(可选包含分数)

使用示例

  1. 基本用法:
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie"
(integer) 3
127.0.0.1:6379> ZREVRANGE scores 0 -1  # 获取全部元素(降序)
1) "Charlie"
2) "Bob"
3) "Alice"
  1. 带分数返回:
127.0.0.1:6379> ZREVRANGE scores 0 1 WITHSCORES  # 获取前两名
1) "Charlie"
2) "300"
3) "Bob"
4) "200"

注意事项

  1. 已弃用:Redis 6.2+建议改用ZRANGE key start stop REV
  2. 索引越界时自动截断
  3. 键不存在时返回空列表

典型应用场景

  1. 排行榜(显示前N名)
127.0.0.1:6379> ZREVRANGE leaderboard 0 9 WITHSCORES
  1. 优先级队列(处理高优先级任务)
  2. 时间线(最新内容优先)

ZPOPMAX

命令格式:

ZPOPMAX key [count]

移除并返回有序集合中分数最高的成员(默认返回1个)

核心特性

  1. 原子性操作:同时完成查询和删除操作
  2. 排序规则:按分数降序返回(最高分在前)
  3. 默认行为:未指定count时只返回1个成员

时间复杂度:O(log(N)*M),N是有序集合基数,M是返回元素数

返回值:被移除的成员及其分数(数组形式)

使用示例

  1. 基本用法:
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie"
(integer) 3
127.0.0.1:6379> ZPOPMAX scores  # 移除并返回最高分成员
1) "Charlie"
2) "300"
  1. 批量移除:
127.0.0.1:6379> ZPOPMAX scores 2  # 移除前两名
1) "Bob"
2) "200"
3) "Alice"
4) "100"
  1. 异常情况:
# 键不存在时
127.0.0.1:6379> ZPOPMAX not_exists
(empty array)

# 错误数据类型时
127.0.0.1:6379> SET wrong_type "value"
OK
127.0.0.1:6379> ZPOPMAX wrong_type
(error) WRONGTYPE Operation against a key holding the wrong kind of value

注意事项

  1. count限制
    • 必须为非负整数
    • 超过集合大小时返回全部元素
  2. 数据修改:操作后成员会从集合中永久移除
  3. 替代命令:Redis 6.2+推荐使用ZRANGE+ZREM组合实现类似功能

典型应用场景

  1. 任务队列(处理高优先级任务)
127.0.0.1:6379> ZPOPMAX pending_tasks
  1. 实时排行榜(获取当日冠军)
127.0.0.1:6379> ZPOPMAX daily_ranking WITHSCORES
  1. 流量控制(处理最高权重请求)

ZPOPMIN

用法和 ZPOPMAX 类似,这里不再赘述

ZRANK、ZREVRANK

1. 基本功能

  • ZRANK:返回成员在有序集合中的升序排名(分数从低到高),排名从0开始计算,最低分成员排名为0
  • ZREVRANK:返回成员在有序集合中的降序排名(分数从高到低),排名从0开始计算,最高分成员排名为0

2. 命令格式

ZRANK key member [WITHSCORE]
ZREVRANK key member [WITHSCORE]

3. 共同特性

  • 时间复杂度:O(log(N))
  • 返回值类型:
    • 成员存在时返回整数排名
    • 成员不存在或key不存在时返回nil
    • Redis 7.2+支持WITHSCORE选项可同时返回分数(返回数组格式[排名,分数])

4. 核心区别

特性 ZRANK ZREVRANK
排序方向 分数升序(低→高) 分数降序(高→低)
最高分排名 最大排名值 0
最低分排名 0 最大排名值

5. 使用示例

# 创建测试数据
127.0.0.1:6379> ZADD leaderboard 100 "Alice" 200 "Bob" 300 "Charlie"

# ZRANK示例(升序排名)
127.0.0.1:6379> ZRANK leaderboard "Alice"  # 最低分→排名0
(integer) 0
127.0.0.1:6379> ZRANK leaderboard "Charlie"  # 最高分→排名2
(integer) 2

# ZREVRANK示例(降序排名)
127.0.0.1:6379> ZREVRANK leaderboard "Alice"  # 最低分→排名2
(integer) 2
127.0.0.1:6379> ZREVRANK leaderboard "Charlie"  # 最高分→排名0
(integer) 0

# WITHSCORE选项(Redis 7.2+)
127.0.0.1:6379> ZREVRANK leaderboard "Bob" WITHSCORE
1) (integer) 1
2) "200"

6. 应用场景

  • ZRANK适用场景

    • 需要知道成员在整体中的相对位置(如成绩百分位)
    • 按成本/价格从低到高排序的场景
  • ZREVRANK适用场景

    • 排行榜系统(显示TOP N用户)
    • 按热度/评分从高到低排序的场景

7. 注意事项

  • 两个命令都采用0-based排名体系
  • 分数相同的成员按字典序决定排名
  • 大集合中使用时要注意O(log(N))的时间复杂度

ZSCORE 指令详解

1. 基本功能

返回有序集合中指定成员的分数值。如果成员不存在或key不存在,返回nil

2. 命令格式

ZSCORE key member

3. 核心特性

  • 时间复杂度:O(1)
  • 返回值类型:
    • 字符串形式返回双精度浮点数分数值
    • 成员不存在时返回nil
    • Redis 7.2+支持WITHSCORE选项可同时返回排名和分数

4. 使用示例

# 创建测试数据
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie"

# 查询成员分数
127.0.0.1:6379> ZSCORE scores "Alice"
"100"

# 不存在的成员
127.0.0.1:6379> ZSCORE scores "David"
(nil)

# 错误数据类型
127.0.0.1:6379> SET wrong_type "value"
OK
127.0.0.1:6379> ZSCORE wrong_type "test"
(error) WRONGTYPE Operation against a key holding the wrong kind of value

5. 应用场景

  • 排行榜系统(查看用户得分)
  • 优先级任务检查(确认任务优先级)
  • 游戏计分系统(查询玩家分数)

ZREM 指令详解

1. 基本功能

从有序集合中移除一个或多个成员,不存在的成员会被忽略

2. 命令格式

ZREM key member [member ...]

3. 核心特性

  • 时间复杂度:O(M*log(N)),M为移除成员数,N为集合基数
  • 返回值:实际移除的成员数量(不包含不存在的成员)
  • 支持批量操作(Redis 2.4+)

4. 使用示例

# 创建测试数据
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie"

# 移除单个成员
127.0.0.1:6379> ZREM scores "Alice"
(integer) 1

# 批量移除
127.0.0.1:6379> ZREM scores "Bob" "David"  # David不存在
(integer) 1

# 错误数据类型
127.0.0.1:6379> SET wrong_type "value"
OK
127.0.0.1:6379> ZREM wrong_type "test"
(error) WRONGTYPE Operation against a key holding the wrong kind of value

5. 应用场景

  • 排行榜更新(移除过期用户)
  • 任务队列管理(完成的任务移出队列)
  • 实时数据清理(移除过期数据)

6. 注意事项

  • 与ZREMRANGEBYRANK不同,ZREM是按成员值移除而非排名
  • 大集合批量移除时建议使用管道(pipeline)提高效率

ZREMRANGEBYRANK

1. 基本功能

移除有序集合中指定排名范围内的所有成员,按升序排名(分数从低到高)计算范围。

2. 命令格式

ZREMRANGEBYRANK key start stop

3. 核心特性

  • 时间复杂度O(log(N) + M),其中 N 是集合大小,M 是被移除的成员数量。
  • 排名规则
    • 排名从 0 开始(最低分成员的排名为 0)。
    • 支持负数索引-1 表示最后一个成员,-2 表示倒数第二个,依此类推)。
  • 返回值:被移除的成员数量(若 key 不存在或范围无效,返回 0)。

4. 使用示例

# 创建测试数据
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie" 400 "David" 500 "Eve"

# 移除排名 0-2(最低分的3个成员)
127.0.0.1:6379> ZREMRANGEBYRANK scores 0 2
(integer) 3  # 移除了 Alice(100), Bob(200), Charlie(300)

# 检查剩余成员
127.0.0.1:6379> ZRANGE scores 0 -1 WITHSCORES
1) "David"
2) "400"
3) "Eve"
4) "500"

# 使用负数索引(移除倒数2个成员)
127.0.0.1:6379> ZREMRANGEBYRANK scores -2 -1
(integer) 2  # 移除了 David(400), Eve(500)

# 检查是否为空
127.0.0.1:6379> ZRANGE scores 0 -1
(empty array)

5. 应用场景

  • 排行榜清理(定期移除排名最低的N个用户)
  • 数据分页删除(批量移除指定范围的记录)
  • 缓存淘汰策略(移除低优先级数据)

6. 注意事项

  • ZREMRANGEBYSCORE 的区别
    • ZREMRANGEBYRANK排名移除(基于排序后的位置)。
    • ZREMRANGEBYSCORE分数范围移除(如 ZREMRANGEBYSCORE scores 100 300)。
  • 索引越界
    • start 超过最大排名,不会移除任何成员。
    • stop 超过最大排名,会截断到最后一个成员。
  • 键不存在时:返回 0,不会报错。

7. 替代方案(Redis 6.2+)

# 使用 ZRANGE + ZREM 组合(适用于复杂条件删除)
127.0.0.1:6379> ZRANGE scores 0 2 BYSCORE | xargs redis-cli ZREM scores

总结ZREMRANGEBYRANK 适用于按排名批量删除,适合排行榜维护、数据清理等场景,使用时需注意排名方向和索引范围。

ZREMRANGEBYSCORE

1. 基本功能

移除有序集合中分数在指定范围内的所有成员(包含 minmax 边界值)。

2. 命令格式

ZREMRANGEBYSCORE key min max

3. 核心特性

  • 时间复杂度O(log(N) + M)N 是集合大小,M 是被移除的成员数量。
  • 分数范围
    • 默认包含边界值(如 ZREMRANGEBYSCORE key 100 200 移除分数 100 ≤ score ≤ 200 的成员)。
    • 支持开区间(使用 ( 符号,如 (100 表示 >100,200 表示 ≤200)。
    • 支持特殊值 -inf(负无穷)和 +inf(正无穷)。
  • 返回值:被移除的成员数量(若 key 不存在或范围无效,返回 0)。

4. 使用示例

# 创建测试数据
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob" 300 "Charlie" 400 "David" 500 "Eve"

# 移除分数 200 ≤ score ≤ 400 的成员
127.0.0.1:6379> ZREMRANGEBYSCORE scores 200 400
(integer) 3  # 移除了 Bob(200), Charlie(300), David(400)

# 检查剩余成员
127.0.0.1:6379> ZRANGE scores 0 -1 WITHSCORES
1) "Alice"
2) "100"
3) "Eve"
4) "500"

# 使用开区间(移除分数 >100 且 ≤300 的成员)
127.0.0.1:6379> ZREMRANGEBYSCORE scores (100 300
(integer) 1  # 仅移除了 Bob(200)

# 使用 -inf 和 +inf(移除所有成员)
127.0.0.1:6379> ZREMRANGEBYSCORE scores -inf +inf
(integer) 2  # 移除了剩余 Alice(100), Eve(500)

5. 应用场景

  • 数据清理(如删除过期低分数据)。
  • 动态排行榜维护(定期移除低活跃用户)。
  • 范围任务处理(批量移除特定优先级的任务)。

6. 注意事项

  • ZREMRANGEBYRANK 区别
    • ZREMRANGEBYSCORE分数范围移除。
    • ZREMRANGEBYRANK排名范围移除(如 ZREMRANGEBYRANK scores 0 2)。
  • 键不存在时:返回 0,无错误。
  • 错误类型:若键存在但非有序集合,返回 WRONGTYPE 错误。

7. 替代方案(复杂条件删除)

# 使用 ZRANGEBYSCORE + ZREM 组合(适用于非连续范围)
127.0.0.1:6379> ZRANGEBYSCORE scores 100 300 | xargs redis-cli ZREM scores

总结ZREMRANGEBYSCORE 适用于按分数批量删除,支持灵活的范围设定,适合数据过滤和动态集合维护场景。

ZINCRBY 指令详解

1. 基本功能

对有序集合中的指定成员进行分数增减操作。若成员不存在,则自动创建并设置初始分数为 0.0 后增减;若键不存在,则创建新有序集合并添加该成员。

2. 命令格式

ZINCRBY key increment member

3. 核心特性

  • 时间复杂度O(log(N))N 为有序集合的成员数量。
  • 分数规则
    • increment 可为正数(增加分数)或负数(减少分数)。
    • 支持双精度浮点数(如 3.14-1.5)。
  • 键和成员处理
    • key 不存在,自动创建新有序集合。
    • member 不存在,视为初始分数 0.0 并增减。
    • key 存在但非有序集合,返回错误。

4. 使用示例

# 初始数据
127.0.0.1:6379> ZADD scores 100 "Alice" 200 "Bob"

# 增加 Alice 的分数 (+50)
127.0.0.1:6379> ZINCRBY scores 50 "Alice"
"150"  # 新分数

# 减少 Bob 的分数 (-30)
127.0.0.1:6379> ZINCRBY scores -30 "Bob"
"170"  # 新分数

# 不存在的成员(自动创建,初始分数 0 + 10)
127.0.0.1:6379> ZINCRBY scores 10 "Charlie"
"10"

# 错误示例(键存在但非有序集合)
127.0.0.1:6379> SET wrong_type "value"
OK
127.0.0.1:6379> ZINCRBY wrong_type 5 "test"
(error) WRONGTYPE Operation against a key holding the wrong kind of value

5. 应用场景

  • 实时排行榜更新(如游戏积分变动)。
  • 优先级任务调整(动态修改任务优先级)。
  • 计数器系统(支持增减的浮点计数器)。

6. 注意事项

  • 返回值:始终返回成员增减后的新分数(字符串形式的浮点数)。
  • 精度问题:浮点数运算可能存在微小误差,需业务层处理。
  • 性能:高频操作时建议使用管道(pipeline)优化。

7. 对比其他命令

  • ZADD 区别:ZINCRBY 专用于增量修改,而 ZADD 直接覆盖分数。
  • HINCRBY 区别:HINCRBY 用于哈希结构且仅支持整数增减。

总结ZINCRBY 是动态维护有序集合分数的核心命令,适用于需频繁增减分数的场景,如排行榜、优先级队列等。

等等,我知道你想问什么,ZADD 好像已经有了 ZINCRBY 的功能呀,那为什么还要保留这个命令呢?感兴趣可以展开看看:

集合间操作指令

ZINTERSTORE 指令深度解析

1. 核心功能

计算多个有序集合的交集,并将结果存储到指定的目标键中。仅保留同时存在于所有输入集合的成员,其分数通过可配置的聚合规则计算。


2. 完整命令格式

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

3. 参数详解

3.1 必选参数
  • destination:存储结果的键名。若已存在会被覆盖(无论原类型)。
  • numkeys:指定参与计算的有序集合数量(必须与实际输入的key数量一致)。
  • key [key …]:参与交集的集合键名(至少1个)。
3.2 可选参数
WEIGHTS
  • 作用:为每个输入集合的分数设置权重乘法因子。
  • 规则
    • 权重数量必须与numkeys一致,未指定时默认为1
    • 支持浮点数(如2.5),可正可负。
  • 示例
# 集合1分数×10,集合2分数×0.5
ZINTERSTORE result 2 set1 set2 WEIGHTS 10 0.5
AGGREGATE
  • 作用:控制交集成员的分数计算方式。
  • 选项
    • SUM(默认):各集合分数×权重后相加
    • MIN:取各集合分数×权重后的最小值
    • MAX:取各集合分数×权重后的最大值
  • 示例
# 取分数的最小值
ZINTERSTORE result 2 set1 set2 AGGREGATE MIN

4. 执行逻辑

  1. 交集判定:仅保留所有输入集合中均存在的成员。
  2. 分数计算
    • 对每个成员,按WEIGHTS对原始分数加权。
    • AGGREGATE规则聚合加权后的分数。
  3. 存储结果:覆盖destination键,类型转为有序集合。

5. 时间复杂度

  • O(NK) + O(Mlog(M))
    • N:最小输入集合的成员数。
    • K:输入集合数量。
    • M:结果集的成员数。

下面是对于这个时间复杂度的说明,感兴趣可以展开看看:


6. 使用示例

6.1 基础交集
# 创建测试数据
ZADD set1 1 "A" 2 "B"
ZADD set2 2 "B" 3 "C"

# 计算交集(默认SUM聚合)
ZINTERSTORE result 2 set1 set2
# 结果: "B"的分数=2(set1)+2(set2)=4
6.2 加权与聚合
# 加权计算(set1分数×10,set2分数×0.1)
ZINTERSTORE result 2 set1 set2 WEIGHTS 10 0.1
# "B"的分数=2×10 + 2×0.1=20.2

# MIN聚合
ZINTERSTORE result 2 set1 set2 AGGREGATE MIN
# "B"的分数=min(2, 2)=2
6.3 错误处理
# 键类型错误(非有序集合)
SET wrong_type "value"
ZINTERSTORE result 1 wrong_type
# 返回: (error) WRONGTYPE

7. 应用场景

  • 共同好友统计:计算多个用户的共同关注列表。
  • 商品筛选:找出同时满足多个条件的商品(如价格区间+评分区间)。
  • 优先级任务合并:整合多来源的高优先级任务。

8. 注意事项

  1. 覆盖风险:目标键会被强制覆盖,包括类型转换。
  2. 权重顺序WEIGHTS顺序需与输入集合顺序严格对应。
  3. 空集合处理:若输入集合无交集,结果集为空(返回0)。
  4. 性能影响:大集合交集的CPU和内存消耗较高,建议在低峰期执行。

ZUNIONSTORE

该指令用法和 ZINERSTORE 相同,故不再赘述,下面是使用示例:

1. 基础并集计算

# 创建两个有序集合
ZADD set1 1 "A" 2 "B"
ZADD set2 2 "B" 3 "C"

# 计算并集(默认SUM聚合)
ZUNIONSTORE result 2 set1 set2
# 结果: "A"(1), "B"(4=2+2), "C"(3)

2. 使用权重(WEIGHTS)

# 集合1分数×10,集合2分数×0.5
ZUNIONSTORE result 2 set1 set2 WEIGHTS 10 0.5
# 结果: "A"(10=1×10), "B"(21=2×10 + 2×0.5), "C"(1.5=3×0.5)

3. 聚合规则(AGGREGATE)

# MIN聚合(取最小分数)
ZUNIONSTORE result 2 set1 set2 AGGREGATE MIN
# 结果: "A"(1), "B"(2), "C"(3)

# MAX聚合(取最大分数)
ZUNIONSTORE result 2 set1 set2 AGGREGATE MAX
# 结果: "A"(1), "B"(2), "C"(3)

4. 多集合并集

# 三个集合的并集
ZADD set3 4 "B" 5 "D"
ZUNIONSTORE result 3 set1 set2 set3
# 结果: "A"(1), "B"(8=2+2+4), "C"(3), "D"(5)

5. 异常处理

# 键不存在时
ZUNIONSTORE result 1 non_existing_key
# 结果: (integer) 0

# 键类型错误(非有序集合)
SET wrong_type "value"
ZUNIONSTORE result 1 wrong_type
# 结果: (error) WRONGTYPE

Zset 相关指令汇总表

命令 时间复杂度 说明
基本操作
ZADD key score member [score member ...] O(k * log(n)) k是添加/更新的成员个数,n是集合当前元素总数
ZCARD key O(1) 获取有序集合的基数(成员数量)
ZSCORE key member O(1) 获取指定成员的分数值
排名查询
ZRANK key member O(log(n)) 获取成员升序排名(从0开始计)
ZREVRANK key member O(log(n)) 获取成员降序排名
增删操作
ZREM key member [member ...] O(k * log(n)) k是删除的成员个数
ZINCRBY key increment member O(log(n)) 对成员分数进行增量操作(原子性)
范围查询
ZRANGE key start end [WITHSCORES] O(log(n) + k) k是返回的成员个数(原图公式顺序有误,已修正)
ZREVRANGE key start end [WITHSCORES] O(log(n) + k) 降序版的ZRANGE
ZRANGEBYSCORE key min max [WITHSCORES] O(log(n) + k) 按分数区间升序查询
ZREVRANGEBYSCORE key max min [WITHSCORES] O(log(n) + k) 按分数区间降序查询
统计操作
ZCOUNT key min max O(log(n)) 统计分数区间内的成员数量
批量删除
ZREMRANGEBYRANK key start end O(log(n) + k) 按排名区间删除成员
ZREMRANGEBYSCORE key min max O(log(n) + k) 按分数区间删除成员
集合运算
ZINTERSTORE dest numkeys key [key ...] O(nk) + O(mlog(m)) n是最小输入集合大小,k是集合数,m是结果集大小
ZUNIONSTORE dest numkeys key [key ...] O(n) + O(m*log(m)) n是输入集合总大小,m是结果集大小

内部编码

以下是整理后的Markdown格式内容:

有序集合类型的内部编码有两种:

1. ziplist(压缩列表)

  • 使用条件
    • 元素个数 < zset-max-ziplist-entries(默认128)
    • 每个元素值大小 < zset-max-ziplist-value(默认64字节)
  • 优势:有效减少内存使用
  • 示例
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
(integer) 3
127.0.0.1:6379> object encoding zsetkey
"ziplist"

2. skiplist(跳表)

  • 使用条件:当不满足ziplist条件时自动切换
  • 原因:元素过多或过大时,ziplist操作效率会下降
  • 示例1(元素数量超过限制)
127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 ... e129
(integer) 129
127.0.0.1:6379> object encoding zsetkey
"skiplist"
  • 示例2(元素大小超过限制)
127.0.0.1:6379> zadd zsetkey 50 "超长字符串...(超过64字节)..."
(integer) 1
127.0.0.1:6379> object encoding zsetkey
"skiplist"

配置参数

参数名 默认值 说明
zset-max-ziplist-entries 128 使用ziplist的最大元素个数
zset-max-ziplist-value 64 使用ziplist的单个元素最大字节数

应用场景

1. 实时排行榜系统

游戏积分排行榜

  • 使用 ZADD 添加玩家分数
  • ZREVRANGE 获取前N名玩家
  • ZINCRBY 实时更新玩家分数
ZADD game_leaderboard 1500 "player1" 2000 "player2" 1800 "player3"
ZREVRANGE game_leaderboard 0 9 WITHSCORES  # 获取TOP10
ZINCRBY game_leaderboard 50 "player1"      # 玩家1增加50分

微博热搜榜

  • 使用 ZINCRBY 增加话题热度
  • ZREVRANGE 获取实时热搜
ZINCRBY weibo_trending 1000000 "#世界杯决赛#"
ZINCRBY weibo_trending 500000 "#元旦假期安排#"
ZREVRANGE weibo_trending 0 4 WITHSCORES  # 获取TOP5热搜

2. 延迟队列系统

订单超时处理

  • 使用分数存储执行时间戳
  • 定时任务获取到期订单
ZADD delay_queue 1672531200 "order_123"  # 2023-01-01 00:00:00执行
ZRANGEBYSCORE delay_queue 0 1672531200  # 获取到期订单

3. 滑动窗口限流

API访问频率控制

  • 使用时间戳作为分数
  • 统计窗口内请求数
ZADD api_limit 1672500000 "req_1"
ZADD api_limit 1672500001 "req_2"
ZREMRANGEBYSCORE api_limit 0 1672500000  # 清理1秒前的请求
ZCARD api_limit                          # 获取当前秒内请求数

4. 带权重的投票系统

热门内容评选

  • 不同用户投票权重不同
  • 实时计算内容得分
ZADD content_votes 5 "article_123"  # 初始5票
ZINCRBY content_votes 2 "article_123"  # VIP用户投票权重为2
ZREVRANGE content_votes 0 9 WITHSCORES  # 获取TOP10内容

5. 时间线排序

朋友圈动态

  • 使用发布时间戳作为分数
  • 获取最新动态
ZADD friend_timeline 1672500000 "post_123"  # 发布动态
ZREVRANGE friend_timeline 0 19  # 获取最新20条动态

6. 多维度排序

商品综合排序

  • 使用加权分数计算综合评分
  • 销量、好评率、价格等多维度
ZADD product_rank 85 "product_123"  # 初始综合分85
ZINCRBY product_rank 5 "product_123"  # 销量增加提升排名

7. 实时竞赛系统

在线编程比赛

  • 实时更新选手得分
  • 获取实时排名
ZADD coding_contest 3 "user_123"  # 3道题正确
ZINCRBY coding_contest 1 "user_123"  # 又解决1题
ZREVRANK coding_contest "user_123"  # 获取用户排名

8. 热点数据缓存

新闻点击排行

  • 记录点击事件
  • 实时统计热点
ZADD news_clicks 1500 "news_123"  # 初始点击量
ZINCRBY news_clicks 1 "news_123"  # 用户点击+1
ZREVRANGE news_clicks 0 9  # 获取TOP10热点新闻

ZSet的这些特性使其成为处理需要实时排序和加权计算场景的理想选择,性能优异且实现简洁。