Redis 有序集合

Redis 有序集合简介

Redis 有序集合是按关联分数排序的唯一字符串(成员)集合。当多个字符串具有相同分数时,字符串按字典顺序排序。有序集合的一些用例包括

  • 排行榜。例如,您可以使用有序集合轻松维护大型在线游戏中最高分数的有序列表。
  • 速率限制器。特别地,您可以使用有序集合构建滑动窗口速率限制器,以防止过多的 API 请求。

您可以将有序集合视为集合和哈希的混合。与集合一样,有序集合由唯一的、非重复的字符串元素组成,因此在某种意义上,有序集合也是一个集合。

但是,虽然集合中的元素没有排序,但有序集合中的每个元素都与一个浮点值相关联,称为分数(这就是类型也类似于哈希的原因,因为每个元素都映射到一个值)。

此外,有序集合中的元素是按顺序取出的(因此它们不是按请求排序的,顺序是用于表示有序集合的数据结构的特性)。它们根据以下规则排序

  • 如果 B 和 A 是两个分数不同的元素,则如果 A.score 大于 B.score,则 A > B。
  • 如果 B 和 A 的分数完全相同,则如果 A 字符串在字典序上大于 B 字符串,则 A > B。B 和 A 字符串不能相等,因为排序集只包含唯一元素。

让我们从一个简单的例子开始,我们将添加所有参赛者以及他们在第一场比赛中的得分

如您所见,ZADD 类似于 SADD,但它需要一个额外的参数(放在要添加的元素之前),该参数是分数。 ZADD 也是可变参数的,因此您可以自由指定多个分数-值对,即使在上面的示例中没有使用。

使用排序集,可以很容易地返回按出生年份排序的黑客列表,因为他们实际上已经排序。

实现说明:排序集通过包含跳跃列表和哈希表这两种双端口数据结构实现,因此每次添加元素时,Redis 都执行 O(log(N)) 操作。这很好,但是当我们要求排序元素时,Redis 根本不需要做任何工作,因为它已经排序了。请注意,ZRANGE 的顺序是从低到高,而 ZREVRANGE 的顺序是从高到低。

注意:0 和 -1 表示从元素索引 0 到最后一个元素(-1 在这里的工作方式与 LRANGE 命令一样)。

可以使用 WITHSCORES 参数返回分数。

对范围进行操作

排序集比这更强大。它们可以对范围进行操作。让我们获取所有得分小于等于 10 的参赛者。我们使用 ZRANGEBYSCORE 命令来完成它

我们要求 Redis 返回所有分数在负无穷大到 10 之间(包括两个极端)的元素。

要删除元素,我们只需使用参赛者的姓名调用 ZREM。还可以删除范围内的元素。让我们删除参赛者 Castilla 以及所有得分严格小于 10 的参赛者

ZREMRANGEBYSCORE 可能不是最好的命令名称,但它非常有用,并返回已删除元素的数量。

另一个对排序集元素定义的极其有用的操作是获取排名操作。可以询问元素在排序元素集中所处的位置。 ZREVRANK 命令也可以用于获取排名,但要考虑按降序排序的元素。

字典序分数

在 Redis 2.8 版本中,引入了一项新功能,允许在字典序上获取范围,假设排序集中所有元素都使用相同的分数插入(元素使用 C memcmp 函数进行比较,因此保证没有整理,并且每个 Redis 实例都将以相同的输出进行回复)。

用于操作字典序范围的主要命令是 ZRANGEBYLEXZREVRANGEBYLEXZREMRANGEBYLEXZLEXCOUNT

例如,让我们再次添加著名黑客列表,但这次对所有元素使用零分数。我们将看到,由于排序集排序规则,它们已经按字典序排序。使用 ZRANGEBYLEX,我们可以要求字典序范围

范围可以是包含的或排除的(取决于第一个字符),字符串无穷大和小无穷大分别用 +- 字符串指定。有关更多信息,请参阅文档。

此功能很重要,因为它允许我们将排序集用作通用索引。例如,如果您要按 128 位无符号整数参数索引元素,您只需将元素添加到排序集中,并使用相同的分数(例如 0),但使用 16 字节前缀,该前缀由 **128 位数字的大端序** 组成。由于大端序数字在字典序(以原始字节顺序)上排序时实际上也是按数字排序的,因此您可以在 128 位空间中要求范围,并获取元素的值,丢弃前缀。

更新分数:排行榜

在切换到下一个主题之前,关于排序集的最后一点说明。排序集的分数可以在任何时候更新。只需对排序集中已包含的元素调用 ZADD,就会以 O(log(N)) 时间复杂度更新其分数(和位置)。因此,排序集适用于更新频繁的情况。

由于这种特性,排行榜是一个常见的用例。典型的应用是 Facebook 游戏,您可以在其中结合获取按最高分排序的用户的功能和获取排名操作,以便显示前 N 个用户以及用户在排行榜中的排名(例如,“您是这里排名第 4932 的最佳得分”)。

示例

  • 我们可以用两种方式使用排序集来表示排行榜。如果我们知道参赛者的新分数,我们可以通过 ZADD 命令直接更新它。但是,如果我们想在现有分数上添加分数,我们可以使用 ZINCRBY 命令。

您将看到,当成员已存在(分数已更新)时,ZADD 返回 0,而 ZINCRBY 返回新分数。参赛者 Henshaw 的分数从 100 变成了 150,不考虑之前的分数是什么,然后又增加了 50,变成了 200。

基本命令

  • ZADD 将新成员及其关联的分数添加到排序集。如果成员已存在,则更新分数。
  • ZRANGE 返回排序集中成员,按给定范围内排序。
  • ZRANK 返回所提供成员的排名,假设排序集按升序排序。
  • ZREVRANK 返回所提供成员的排名,假设排序集按降序排序。

查看 排序集命令的完整列表

性能

大多数排序集操作为 O(log(n)),其中 n 是成员数。

在使用 ZRANGE 命令返回大量结果时(例如,数万个或更多),请注意。此命令的时间复杂度为 O(log(n) + m),其中 m 是返回的结果数。

替代方案

Redis 排序集有时用于索引其他 Redis 数据结构。如果您需要索引和查询数据,请考虑 JSON 数据类型和 搜索和查询 功能。

了解更多

RATE THIS PAGE
Back to top ↑