引言

Redis 是一个开源的、内存中的键值数据存储。 在 Redis,排序集是一种类似于集的数据类型,两者都是不重复的字符串组。 不同之处在于,排序集中的每个成员都与一个分数相关联,允许从最小分数到最大分数进行排序。 与集合一样,排序集合中的每个成员必须是唯一的,尽管多个成员可以共享相同的得分。

本教程说明如何创建排序集、检索和删除其成员,以及如何从现有的排序集创建新的排序集。

如何使用本指南

本指南是作为包含自包含示例的备忘单编写的。 我们鼓励您跳转到任何与您正在尝试完成的任务相关的部分。

本指南中显示的命令是在运行 Redis 4.0.9版本的 Ubuntu 18.04服务器上测试的。 要建立一个类似的环境,你可以按照我们关于如何在 Ubuntu 18.04上安装和保护 Redis 的指南的第一步。 我们将通过使用 Redis-cli (Redis 命令行界面)运行这些命令来演示它们的行为。 请注意,如果您使用的是不同的 Redis 接口ーー例如 Redli ーー某些命令的确切输出可能会有所不同。

或者,您可以提供一个托管 Redis 数据库实例来测试这些命令,但是请注意,根据您的数据库提供程序所允许的控制级别,本指南中的某些命令可能不能像描述的那样工作。 要提供一个数字数据库管理数据库,请遵循我们的管理数据库产品文档。 然后,必须安装 Redli 或设置 TLS 通道,以便通过 TLS 连接到托管数据库。

创建排序集和添加成员

若要创建排序集,请使用 zadd 命令。 Zadd 接受用于存储排序集的键的名称作为参数,后面跟着要添加的成员的得分和成员本身的值。 下面的命令将创建一个名为 faveGuitarists 的排序集关键字,其中一个成员“ Joe Pass”的得分为1:

  • zadd faveGuitarists 1 "Joe Pass"

Zadd 将返回一个整数,该整数指示在成功创建排序集时向该排序集添加了多少成员。

Output
(integer) 1

您可以向使用 zadd 的排序集中添加多个成员。 注意,他们的分数不需要按顺序排列,分数之间可以有间隔,同一排序集中的多个成员可以共享相同的分数:

  • zadd faveGuitarists 4 "Stephen Malkmus" 2 "Rosetta Tharpe" 3 "Bola Sete" 3 "Doug Martsch" 8 "Elizabeth Cotten" 12 "Nancy Wilson" 4 "Memphis Minnie" 12 "Michael Houser"
Output
(integer) 8

Zadd 可以接受以下选项,您必须在键名之后和第一个成员得分之前输入:

  • Nx 或 XX: 这些选项具有相反的效果,因此您只能在任何 zadd 操作中包含它们中的一个: NX: 告诉 zadd 不要更新现有成员。 使用这个选项,zadd 将只添加新元素。 Xx: 告诉 zadd 只更新现有元素。 使用这个选项,zadd 将永远不会添加新成员。
  • Ch: 通常,zadd 只返回添加到排序集中的新元素的数量。 不过,如果包含了这个选项,zadd 将返回数字更改过的元素。 这包括新加入的成员和分数改变的成员。
  • Incr: 这会导致命令增加成员的得分值。 如果成员还不存在,命令将把它添加到排序集中,并将增量作为其分数,就好像它的原始分数是0一样。 包括 INCR,zadd 将返回成员的新分数,如果它是成功的。 请注意,在使用此选项时,每次只能包含一个 score / member 对。

与传递 INCR 选项到 zadd 相反,您可以使用行为完全相同的 zincrby 命令。 而不是给排序集成员的值所指示的得分值,如 zadd,它递增该成员的得分由该值。 例如,下面的命令增加成员“ Stephen Malkmus”的得分,最初是4,增加了5到9。

  • zincrby faveGuitarists 5 "Stephen Malkmus"
Output
"9"

与 zadd 命令的 INCR 选项一样,如果指定的成员不存在,那么 zincrby 将用增量值作为其得分创建它。

从已排序集中检索成员

检索排序集中保存的成员的最基本方法是使用 zrange 命令。 此命令接受要检索其成员的密钥的名称以及其中包含的成员范围作为参数。 范围由两个表示从零开始的索引的数字定义,这意味着0表示排序集中的第一个成员(或者,得分最低的成员) ,1表示下一个成员,依此类推。

下面的例子将返回在前一节中创建的 faveGuitarists 的前四个成员:

  • zrange faveGuitarists 0 3
Output
1) "Joe Pass" 2) "Rosetta Tharpe" 3) "Bola Sete" 4) "Doug Martsch"

注意,如果传递给 zrange 的排序集有两个或多个元素共享相同的得分,那么它将按照字典排序或字母顺序对这些元素进行排序。

启动和停止索引也可以是负数,-1表示最后一个成员,-2表示倒数第二个成员,依此类推:

  • zrange faveGuitarists -5 -2
Output
1) "Memphis Minnie" 2) "Elizabeth Cotten" 3) "Stephen Malkmus" 4) "Michael Houser"

可以接受 WITHSCORES 参数,当包含这个参数时,它也会返回成员的得分:

  • zrange faveGuitarists 5 6 WITHSCORES
Output
1) "Elizabeth Cotten" 2) "8" 3) "Stephen Malkmus" 4) "9"

Zrange 只能按数字顺序返回一个成员范围。 要逆转这一点并按降序返回一个范围,必须使用 zrevrange 命令。 可以将这个命令看作是在返回指定范围内的成员之前临时颠倒给定排序集的顺序。 所以对于 zrevrange,0表示键中最后一个成员,1表示倒数第二个成员,以此类推:

  • zrevrange faveGuitarists 0 5
Output
1) "Nancy Wilson" 2) "Michael Houser" 3) "Stephen Malkmus" 4) "Elizabeth Cotten" 5) "Memphis Minnie" 6) "Doug Martsch"

Zrevrange 也可以接受 WITHSCORES 选项。

您可以使用 zrangebyscore 命令根据成员的分数返回一个范围的成员。 在下面的示例中,该命令将返回 faveGuitarists 键中所有得分为2、3或4的成员:

  • zrangebyscore faveGuitarists 2 4
Output
1) "Rosetta Tharpe" 2) "Bola Sete" 3) "Doug Martsch" 4) "Memphis Minnie"

在这个示例中,范围是包含的,这意味着它将返回分数为2或4的成员。 您可以通过在范围的前面加上开括号(()来排除范围的任何一端。 下面的示例将返回分数大于或等于2但小于4的每个成员:

  • zrangebyscore faveGuitarists 2 (4
Output
1) "Rosetta Tharpe" 2) "Bola Sete" 3) "Doug Martsch"

与 zrange 一样,zrangebyscore 可以接受 WITHSCORES 参数。 它还接受 LIMIT 选项,您可以使用它只从 zrangebyscore 输出中检索选定的元素。 此选项接受一个偏移量(标记该命令将返回的范围中的第一个成员)和一个计数(定义该命令将返回的总成员数)。 例如,下面的命令将查看 faveGuitarists sorted set 的前六个成员,但是只返回其中的三个成员,从范围中的第二个成员开始,用1表示:

  • zrangebyscore faveGuitarists 0 5 LIMIT 1 3
Output
1) "Rosetta Tharpe" 2) "Bola Sete" 3) "Doug Martsch"

Zrevrangebyscore 命令根据成员的得分返回一个反向的成员范围。 下面的命令返回集合中的每个成员,其得分在10到6之间:

  • zrevrangebyscore faveGuitarists 10 6
Output
1) "Stephen Malkmus" 2) "Elizabeth Cotten"

和 zrangebyscore 一样,zrevrangebyscore 可以同时接受 WITHSCORES 和 LIMIT 选项。 此外,您可以通过在前面加上开括号来排除范围的任何一端。

可能会有这样的情况: 排序集中的所有成员的得分都相同。 在这种情况下,您可以强制 redis 返回按字母顺序排序的元素范围,或者使用 zrangebylex 命令在字母顺序中返回。 要尝试这个命令,运行以下 zadd 命令创建一个排序集,其中每个成员拥有相同的得分:

  • zadd SomervilleSquares 0 Davis 0 Inman 0 Union 0 porter 0 magoun 0 ball 0 assembly

Zrangebylex 后面必须跟着一个键的名称、一个开始间隔和一个停止间隔。 开始和停止间隔必须以开括号(()或开括号(())开始,如下:

  • zrangebylex SomervilleSquares [a [z
Output
1) "assembly" 2) "ball" 3) "magoun" 4) "porter"

注意,这个示例只返回集合中八个成员中的四个,即使该命令寻求的范围是从 a 到 z。 这是因为 Redis 值是区分大小写的,因此从其输出中排除了以大写字母开头的成员。 要返回这些,你可以运行以下命令:

  • zrangebylex SomervilleSquares [A [z
Output
1) "Davis" 2) "Inman" 3) "Union" 4) "assembly" 5) "ball" 6) "magoun" 7) "porter"

Zrangebylex 还接受特殊字符-,代表负无穷大,+ ,代表正无穷大。 因此,下面的命令语法也将返回排序集的每个成员:

  • zrangebylex SomervilleSquares - +

请注意,zrangebylex 不能按反向字母表顺序(升序字母表顺序)返回排序的集成员。 要做到这一点,可以使用 zrevrangebylex:

  • zrevrangebylex SomervilleSquares + -
Output
1) "porter" 2) "magoun" 3) "ball" 4) "assembly" 5) "Union" 6) "Inman" 7) "Davis"

因为它是用于每个成员拥有相同得分的排序集,所以 zrangebylex 不接受 WITHSCORES 选项。 然而,它确实接受了 LIMIT 选项。

检索有关排序集的信息

要查明给定排序集中有多少个成员(或者,换句话说,确定它的基数) ,可以使用 zcard 命令。 下面的示例显示了本指南第一部分中 faveGuitarists 键中包含的成员数量:

  • zcard faveGuitarists
Output
(integer) 9

Zcount 可以告诉你在一个给定的排序集中有多少元素在分数范围内。 键后的第一个数字是范围的开始,第二个数字是范围的结束:

  • zcount faveGuitarists 3 8
Output
(integer) 4

Zscore 输出排序集合中指定成员的得分:

  • zscore faveGuitarists "Bola Sete"
Output
"3"

如果指定的成员或键不存在,zscore 将返回(nil)。

Zrank 类似于 zscore,但它不返回给定成员的得分,而是返回其排名。 在 Redis,一个排名是一个从零开始的指数的成员排序的集合,由他们的得分排序。 例如,“ Joe Pass”的得分为1,但是因为这是键中任何成员的最低分,所以它的排名为0:

  • zrank faveGuitarists "Joe Pass"
Output
(integer) 0

还有另一个 Redis 命令名为 zrevrank,它执行与 zrank 相同的功能,但是反转了集合中成员的等级。 在下面的例子中,成员“ Joe Pass”的得分最低,因此反排名最高:

  • zrevrank faveGuitarists "Joe Pass"
Output
(integer) 8

一个成员的得分与他们的排名之间唯一的关系是他们的得分与其他成员的得分之间的关系。 如果两个连续成员之间存在分数差距,那么这不会反映在他们的排名中。 请注意,如果两个成员拥有相同的分数,那么按字母顺序排在第一位的成员的排名将较低。

和 zscore 一样,如果密钥或成员不存在,zrank 和 zrevrank 将返回(nil)。

Zlexcount 可以告诉您在一个字典编纂范围之间的排序集中有多少个成员。 下面的示例使用了从前一节中排序的 SomervilleSquares 集:

  • zlexcount SomervilleSquares [M [t
Output
(integer) 5

这个命令遵循与 zrangebylex 命令相同的语法,因此请参阅前面的部分以获得关于如何定义字符串范围的详细信息。

从排序集中删除成员

命令可以从一个排序集中删除一个或多个成员:

  • zrem faveGuitarists "Doug Martsch" "Bola Sete"

Zrem 将返回一个整数,指示它从排序集中删除了多少成员:

Output
(integer) 2

有三个 Redis 命令允许您根据范围移除排序集的成员。 例如,如果排序集中的每个成员具有相同的得分,则可以使用 zrangebylex 根据字典编纂范围删除成员。 此命令使用与 zrangebylex 相同的语法。 下面的示例将从前面部分创建的 SomervilleSquares 键中删除以大写字母开头的所有成员:

  • zremrangebylex SomervilleSquares [A [Z

Zremrangebylex 将输出一个整数,表示删除了多少成员:

Output
(integer) 3

您还可以使用 zrmrangebyscore 命令根据分数范围来删除成员,该命令使用与 zrangebyscore 命令相同的语法。 下面的示例将删除 faveguitists 中所有得分为4、5或6的成员:

  • zremrangebyscore faveGuitarists 4 6
Output
(integer) 1

您可以使用 zrmrangebyrank 命令根据等级范围从集合中删除成员,该命令使用与 zrangebyrank 相同的语法。 下面的命令将删除排序集中排名最低的三个成员,这三个成员由一系列从零开始的索引定义:

  • zremrangebyrank faveGuitarists 0 2
Output
(integer) 3

注意,传递给 remrangebyrank 的数字也可以是负数,-1表示最高的秩,-2表示次高的秩,依此类推。

从现有的排序集创建新的排序集

Redis 包含两个命令,允许您比较多个排序集的成员并基于这些比较创建新的成员: zinterstore 和 zunionstore。 要实验这些命令,请运行以下 zadd 命令来创建一些排序的示例集。

  • zadd NewKids 1 "Jonathan" 2 "Jordan" 3 "Joey" 4 "Donnie" 5 "Danny"
  • zadd Nsync 1 "Justin" 2 "Chris" 3 "Joey" 4 "Lance" 5 "JC"

Zinterstore 找到由两个或多个排序集(它们的交集)共享的成员,并生成一个新的只包含这些成员的排序集。 这个命令必须按顺序包含目标键的名称,在这个目标键中相交的成员将被存储为一个排序集,传递给 zinterstore 的键的数量,以及你想要分析的键的名称:

  • zinterstore BoyBands 2 NewKids Nsync

Zinterstore 将返回一个整数,显示存储到目标排序集的元素数量。 因为 NewKids 和 Nsync 只共享一个成员“ Joey” ,该命令将返回1:

Output
(integer) 1

请注意,如果目标密钥已经存在,zinterstore 将覆盖其内容。

Zunionstore 将创建一个新的分类集,保存传递给它的每个成员的钥匙。 该命令使用与 zinterstore 相同的语法,并要求目标键的名称、传递给命令的键的数量以及键的名称:

  • zunionstore SuperGroup 2 NewKids Nsync

与 zinterstore 一样,zunionstore 将返回一个整数,显示存储在目标键中的元素数量。 即使两个原始的排序集都有5个成员,因为排序集不能有重复成员,而且每个键都有一个名为“ Joey”的成员,所以得到的整数是9:

Output
(integer) 9

与 zinterstore 一样,zunionstore 将覆盖目标键(如果它已经存在)的内容。

为了使您在使用 zinterstore 和 zunionstore 创建新的排序集时能够更好地控制成员得分,这两个命令都接受 WEIGHTS 和 AGGREGATE 选项。

Weights 选项后面跟着一个数字,表示包含在命令中的每个排序集,它加权或乘以每个成员的得分。 Weights 选项后的第一个数字权重第一个键传递给命令的得分,第二个数字权重第二个键,以此类推。

下面的示例创建一个新的排序集,其中包含 NewKids 和 Nsync 排序集的交叉键。 它把 NewKids 键中的分数加权三倍,把 Nsync 键中的分数加权七倍:

  • zinterstore BoyBandsWeighted 2 NewKids Nsync WEIGHTS 3 7

如果不包含 WEIGHTS 选项,那么 zinterstore 和 zunionstore 的权重默认为1。

Aggregate 接受三个子选项。 其中的第一个,SUM,通过在组合集中添加匹配成员的得分来实现 zinterstore 和 zunionstore 的默认行为。

如果你在两个共享一个成员的排序集合上运行 zinterstore 或 zunionstore 操作,但是这个成员在每个集合中有不同的得分,你可以强制操作使用 MIN 子选项分配新集合中两个得分中较低的一个。

  • zinterstore BoyBandsWeightedMin 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MIN

因为这两个排序集合只有一个匹配的成员具有相同的分数(3) ,所以这个命令将创建一个新集合,其成员具有两个加权分数中较低的一个:

  • zscore BoyBandsWeightedMin "Joey"
Output
"9"

同样,AGGREGATE 可以强制 zinterstore 或 zunionstore 使用 MAX 选项分配两个得分中较高的一个:

  • zinterstore BoyBandsWeightedMax 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MAX

这个命令创建一个新集合,其中一个成员为“ Joey” ,它在两个加权得分中得分较高:

  • zscore BoyBandsWeightedMax "Joey"
Output
"21"

认为 WEIGHTS 是一种在分析成员之前暂时操纵他们的得分的方法是有帮助的。 同样地,把 AGGREGATE 选项看作是一种在成员被添加到新集合之前决定如何控制他们的分数的方法也是很有帮助的。

总结

本指南详细介绍了在 Redis 中用于创建和管理排序集的许多命令。 如果还有其他相关的命令、参数或者程序你想在本指南中看到,请在下面的评论中询问或者提出建议。

有关 Redis 命令的更多信息,请参见我们关于如何管理 Redis 数据库的系列教程。