Redis有序集合(ZSET)指南:从入门到精通 – wiki大全

Redis 有序集合(ZSET)指南:从入门到精通

Redis 有序集合(Sorted Set,简称 ZSET)是 Redis 中一种独特且功能强大的数据结构,它结合了哈希表和跳跃表的特点,提供了集合的唯一性以及按照分数(score)进行排序的能力。本文将深入探讨 Redis ZSET 的基本概念、常用命令、应用场景以及一些高级用法,帮助您从入门到精通。

1. 什么是 Redis 有序集合 (ZSET)?

有序集合是字符串的集合,其中每个成员(member)都关联一个分数(score),分数是一个浮点数。ZSET 的主要特点如下:

  • 成员唯一性:集合中的每个成员都是唯一的,不能重复。
  • 有序性:集合中的成员是按照其关联的分数从小到大排序的。如果分数相同,则按照成员的字典顺序(ASCII 码)排序。
  • 高效查找:Redis ZSET 在内部使用跳跃表(skiplist)和哈希表(hash table)实现,因此可以高效地执行范围查询、成员查找、分数更新等操作。
  • 支持范围查询:可以根据分数范围或成员的排名范围来获取成员列表。

2. ZSET 的内部实现

Redis ZSET 的底层实现是结合了两种数据结构:

  1. 哈希表 (Hash Table):用于存储成员(member)到分数(score)的映射。这使得我们可以快速通过成员查找其分数,时间复杂度为 O(1)。
  2. 跳跃表 (Skip List):用于存储所有成员及其分数,并按照分数进行排序。跳跃表是一种概率性数据结构,它允许在 O(log N) 的平均时间复杂度内进行搜索、插入和删除操作。

这种组合使得 ZSET 既能快速查找成员,又能高效地进行范围查询和排序操作。

3. ZSET 常用命令

以下是 Redis ZSET 常用的一些命令及其用法:

3.1 添加成员:ZADD

ZADD key score member [score member ...]

将一个或多个成员及其分数添加到有序集合中。如果成员已经存在,则更新其分数。

示例:

redis
ZADD myzset 1 "member1"
ZADD myzset 2 "member2" 3 "member3"
ZADD myzset 2.5 "member4"

3.2 获取有序集合的成员数量:ZCARD

ZCARD key

返回有序集合中成员的数量。

示例:

“`redis
ZCARD myzset

结果: 4

“`

3.3 获取成员的分数:ZSCORE

ZSCORE key member

返回有序集合中指定成员的分数。

示例:

“`redis
ZSCORE myzset “member2”

结果: “2”

“`

3.4 增加成员的分数:ZINCRBY

ZINCRBY key increment member

给有序集合中指定成员的分数加上增量 increment。如果成员不存在,则添加该成员并设置其分数为 increment

示例:

“`redis
ZINCRBY myzset 10 “member1”

结果: “11” (原分数 1 + 增量 10)

“`

3.5 移除成员:ZREM

ZREM key member [member ...]

从有序集合中移除一个或多个成员。

示例:

“`redis
ZREM myzset “member3”

结果: 1 (表示移除了一个成员)

ZCARD myzset

结果: 3

“`

3.6 范围查询:ZRANGEZREVRANGE

这两个命令用于根据排名(rank)范围获取成员。

ZRANGE key start stop [WITHSCORES]

返回有序集合中排名在 startstop 之间(包含)的成员。排名从 0 开始。startstop 也可以是负数,表示从末尾开始计数 (-1 表示最后一个成员)。

ZREVRANGE key start stop [WITHSCORES]

ZRANGE 类似,但返回的成员是按照分数从大到小排序的。

示例:

“`redis

假设 myzset 成员及分数如下:

(“member1”, 11) (“member2”, 2) (“member4”, 2.5)

ZRANGE 获取排名 0 到 1 的成员 (从小到大排序)

ZRANGE myzset 0 1

结果:

1) “member2”

2) “member4”

ZRANGE 获取排名 0 到 1 的成员及分数

ZRANGE myzset 0 1 WITHSCORES

结果:

1) “member2”

2) “2”

3) “member4”

4) “2.5”

ZREVRANGE 获取排名 0 到 1 的成员 (从大到小排序)

ZREVRANGE myzset 0 1

结果:

1) “member1”

2) “member4”

“`

3.7 分数范围查询:ZRANGEBYSCOREZREVRANGEBYSCORE

这两个命令用于根据分数范围获取成员。

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

返回有序集合中分数在 minmax 之间(包含)的成员。minmax 可以是 -inf (负无穷大) 或 +inf (正无穷大)。使用 ( 表示开区间,例如 (10 表示大于 10。

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

ZRANGEBYSCORE 类似,但按照分数从大到小排序。注意 maxmin 的顺序。

示例:

“`redis

获取分数在 2 到 3 之间的成员

ZRANGEBYSCORE myzset 2 3 WITHSCORES

结果:

1) “member2”

2) “2”

3) “member4”

4) “2.5”

获取分数大于 2.5 的成员

ZRANGEBYSCORE myzset (2.5 +inf

结果:

1) “member1”

“`

3.8 获取成员排名:ZRANKZREVRANK

ZRANK key member

返回有序集合中指定成员的排名(从 0 开始,分数从小到大排序)。如果成员不存在,返回 nil。

ZREVRANK key member

返回有序集合中指定成员的逆序排名(从 0 开始,分数从大到小排序)。

示例:

“`redis
ZRANK myzset “member1”

结果: 2 (因为 member1 分数是 11,是最大的)

ZREVRANK myzset “member1”

结果: 0

“`

3.9 移除指定排名范围的成员:ZREMRANGEBYRANK

ZREMRANGEBYRANK key start stop

移除有序集合中排名在 startstop 之间(包含)的所有成员。

3.10 移除指定分数范围的成员:ZREMRANGEBYSCORE

ZREMRANGEBYSCORE key min max

移除有序集合中分数在 minmax 之间(包含)的所有成员。

3.11 交集和并集:ZINTERSTOREZUNIONSTORE

这两个命令用于计算多个有序集合的交集或并集,并将结果存储到一个新的有序集合中。

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

计算给定 key 的交集,并将结果存储到 destinationWEIGHTS 参数可以为每个输入集合指定权重,成员的分数会乘以权重。AGGREGATE 参数指定如何处理共同成员的分数(求和、取最小值、取最大值)。

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

计算给定 key 的并集,并将结果存储到 destination

示例:

“`redis
ZADD set1 10 “a” 20 “b”
ZADD set2 15 “b” 25 “c”

计算并集,默认 AGGREGATE SUM

ZUNIONSTORE union_set 2 set1 set2

union_set: (“a”, 10) (“b”, 35) (“c”, 25)

计算交集,默认 AGGREGATE SUM

ZINTERSTORE inter_set 2 set1 set2

inter_set: (“b”, 35)

“`

4. ZSET 的应用场景

ZSET 因其独特的排序和范围查询能力,在许多场景下都非常有用:

  1. 排行榜:这是 ZSET 最经典的用途。例如,游戏中的积分排行榜、网站文章点击量排行榜、用户活跃度排行榜等。成员是用户ID或文章ID,分数是积分或点击量。

    • ZADD 更新用户积分/点击量。
    • ZREVRANGE 获取前 N 名用户。
    • ZRANK 获取特定用户的排名。
    • ZRANGEBYSCORE 获取分数在某个范围内的用户。
  2. 最新文章/热门商品列表:根据发布时间(时间戳作为分数)或销售量(销售量作为分数)来展示最新的或最热门的商品/文章。

    • ZADD 添加商品/文章及分数。
    • ZREVRANGE 获取最新或最热门的 N 个商品/文章。
  3. 优先级队列:将任务ID作为成员,任务的优先级作为分数。高分数的任务优先执行。

    • ZADD 添加任务及其优先级。
    • ZRANGE 获取优先级最高的任务(分数最小的)。
  4. 社交应用中的“附近的人”:将用户的地理位置信息(例如经纬度组合成的哈希值)作为分数,用户ID作为成员。通过分数范围查询可以找出附近的用户。

  5. 延迟任务队列:将任务的执行时间戳作为分数,任务ID作为成员。定时从 ZSET 中取出分数小于当前时间戳的任务进行处理。

    • ZADD 添加任务及其执行时间戳。
    • ZRANGEBYSCORE key -inf current_timestamp 获取需要执行的任务。

5. 高级用法和注意事项

  • 分数精度:ZSET 的分数是双精度浮点数,可以支持非常大的范围和精度。
  • 成员字符串长度:成员可以是任意长度的字符串,但过长的字符串会增加内存消耗。
  • 内存使用:ZSET 会消耗比 List 或 Hash 更多的内存,因为它需要同时维护哈希表和跳跃表。当 ZSET 较小(例如,成员数量小于 128 且所有成员的字符串长度小于 64 字节)时,Redis 会采用优化后的 ziplist 编码来节省内存。
  • 原子性:所有 Redis 命令都是原子性的,这意味着 ZSET 的操作是线程安全的。
  • 范围查询优化LIMIT offset count 参数在进行范围查询时非常有用,可以用于分页。

6. 总结

Redis 有序集合(ZSET)是一个多功能且高效的数据结构,它通过结合哈希表和跳跃表,在提供成员唯一性的同时,实现了基于分数的快速排序和范围查询。无论是构建排行榜、实现优先级队列还是处理时间序列数据,ZSET 都能提供强大的支持。掌握 ZSET 的使用,将使您能够更灵活、高效地设计和实现各种 Redis 应用。

滚动至顶部