如何在Redis中管理已排序集合
引言
Redis是一个开源的、内存中的键值数据存储库。在Redis中,有序集合(sorted sets)是一种类似于集合的数据类型,两者都是由字符串组成的非重复组。区别在于有序集合的每个成员都与一个分数相关联,使得它们可以根据分数从最小到最大进行排序。与集合类似,有序集合中的每个成员必须是唯一的,尽管多个成员可以共享相同的分数。
本教程将解释如何创建排序集合,检索和删除其成员,并从现有集合中创建新的排序集合。
如何使用本指南
这个指南是一个自包含示例的备忘单形式写成的。我们鼓励您直接跳转到与您正在尝试完成的任务相关的任何部分。
本指南中显示的命令,在运行Redis版本6.0.16的Ubuntu 22.04服务器上经过测试。要设置类似的环境,您可以按照我们关于如何在Ubuntu 22.04上安装和保护Redis的指南的第一步操作。我们将通过使用Redis命令行界面redis-cli来演示这些命令的行为。如果您使用的是不同的Redis接口,例如Redli,某些命令的确切输出可能会有所不同。
作为另一种选择,你可以提供一个托管的 Redis 数据库实例来测试这些命令。但是,根据你的数据库提供者所允许的控制级别,本指南中的某些命令可能无法按照描述来执行。要提供一个 Silicon Cloud 托管数据库,请参考我们的托管数据库产品文档。然后,你需要安装 Redli 或者设置一个 TLS 隧道,以便通过 TLS 连接到托管数据库。
创建有序集合并添加成员
要创建一个有序集合,请使用zadd命令。zadd命令的参数包括持有有序集合的键名,要添加的成员的分数以及成员本身的值。下面的命令将创建一个名为faveGuitarists的有序集合键,其中包含一个分数为1的成员“Joe Pass”。
- zadd faveGuitarists 1 “Joe Pass”
如果sorted set创建成功,zadd将返回一个整数,表示添加到sorted set的成员数量。
(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”
(integer) 8
zadd可以接受以下选项,在输入键名之后、第一个成员分值之前必须输入:
- NX or XX: These options have opposite effects, so you can only include one of them in any zadd operation:NX: Tells zadd not to update existing members. With this option, zadd will only add new elements.
XX: Tells zadd to only update existing elements. With this option, zadd will never add new members. - CH: Normally, zadd only returns the number of new elements added to the sorted set. With this option included, though, zadd will return the number of changed elements. This includes newly added members and members whose scores were changed.
- INCR: This causes the command to increment the member’s score value. If the member doesn’t yet exist, the command will add it to the sorted set with the increment as its score, as if its original score was 0. With INCR included, the zadd will return the member’s new score if it’s successful. Note that you can only include one score/member pair at a time when using this option.
不需要将INCR选项传递给zadd,您可以使用zincrby命令来达到完全相同的效果。与zadd不同,zincrby不会赋予有序集合成员与分数值相对应的值,而是将该成员的分数增加相应的值。例如,以下命令将原本为4的成员“Stephen Malkmus”的分数增加5,使其变为9。
- zincrby faveGuitarists 5 “Stephen Malkmus”
“9”
与zadd命令的INCR选项一样,如果指定的成员不存在,那么zincrby命令将用增量值作为它的分数来创建该成员。
从有序集合中检索成员
检索已排序集合中的成员的最基本方法是使用zrange命令。此命令接受两个参数:要检索成员的键的名称和其中包含的成员范围。范围由两个数字定义,这两个数字表示以0为基准的索引,即0表示排序集合中的第一个成员(或者得分最低的成员),1表示下一个成员,依此类推。
在前一部分创建的faveGuitarists排序集合中,以下示例将返回前四个成员。
- zrange faveGuitarists 0 3
1) “Joe Pass” 2) “Rosetta Tharpe” 3) “Bola Sete” 4) “Doug Martsch”
请注意,如果您向 zrange 函数传递的有序集合中有两个或更多的元素具有相同的分数,它将按照字典顺序或字母顺序对这些元素进行排序。
起始和结束索引也可以是负数,-1代表最后一个成员,-2代表倒数第二个成员,依此类推。
- zrange faveGuitarists -5 -2
1) “Memphis Minnie” 2) “Elizabeth Cotten” 3) “Stephen Malkmus” 4) “Michael Houser”
zrange可以接受WITHSCORES参数,当包含该参数时,还会返回成员的分数。
- zrange faveGuitarists 5 6 WITHSCORES
1) “Elizabeth Cotten” 2) “8” 3) “Stephen Malkmus” 4) “9”
zrange只能按照升序返回一定范围的成员。要反转顺序并按降序返回一定范围,必须使用zrevrange命令。可以将这个命令视为在返回指定范围内的成员之前临时反转给定有序集合的顺序。因此,使用zrevrange,0代表键中保存的最后一个成员,1代表倒数第二个成员,以此类推。
- zrevrange faveGuitarists 0 5
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
1) “Rosetta Tharpe” 2) “Bola Sete” 3) “Doug Martsch” 4) “Memphis Minnie”
在这个示例中,范围是包含的,意味着它将返回得分为2或4的成员。您可以在范围的任一端之前添加开口括号((),以排除该端。以下示例将返回得分大于或等于2,但小于4的每个成员。
- zrangebyscore faveGuitarists 2 (4
1) “Rosetta Tharpe” 2) “Bola Sete” 3) “Doug Martsch”
与zrange一样,zrangebyscore可以接受WITHSCORES参数。它也接受LIMIT选项,您可以使用它来从zrangebyscore的输出中仅检索部分元素。该选项接受一个偏移量,标记命令将返回的范围中的第一个成员,以及一个计数,定义命令将总共返回多少个成员。例如,以下命令将查看faveGuitarists排序集的前六个成员,但仅返回其中三个成员,从范围中的第二个成员开始,表示为1:
- zrangebyscore faveGuitarists 0 5 LIMIT 1 3
1) “Rosetta Tharpe” 2) “Bola Sete” 3) “Doug Martsch”
zrevrangebyscore命令根据成员的分数返回一个反向范围。以下命令返回分数在10和6之间的集合中的每个成员。
- zrevrangebyscore faveGuitarists 10 6
1) “Stephen Malkmus” 2) “Elizabeth Cotten”
与zrangebyscore一样,zrevrangebyscore可以接受WITHSCORES和LIMIT选项。此外,您可以使范围的任一端排除在外,以开放括号开头。
可能会有时候,一个有序集合中的所有成员都具有相同的分数。在这种情况下,您可以使用zrangebylex命令强制Redis按照字典顺序或字母顺序返回一系列元素。为了尝试这个命令,运行以下zadd命令来创建一个每个成员都具有相同分数的有序集合:
- zadd SomervilleSquares 0 Davis 0 Inman 0 Union 0 porter 0 magoun 0 ball 0 assembly
zrangebylex必须跟着一个键的名称,起始区间和结束区间。起始和结束区间必须以开放括号(())或开放方括号([)开头,如下所示:
- zrangebylex SomervilleSquares [a [z
1) “assembly” 2) “ball” 3) “magoun” 4) “porter”
请注意,即使命令请求了从a到z的范围,但是这个示例只返回了集合中的四个成员,这是因为Redis的值是区分大小写的,所以以大写字母开头的成员被排除在输出之外。要返回这些成员,你可以运行以下命令:
- zrangebylex SomervilleSquares [A [z
1) “Davis” 2) “Inman” 3) “Union” 4) “assembly” 5) “ball” 6) “magoun” 7) “porter”
zrangebylex函数还可以接受特殊字符-,表示负无穷,以及+,表示正无穷。因此,以下命令语法也会返回有序集合的每个成员。
- zrangebylex SomervilleSquares – +
请注意,zrangebylex无法按照字典顺序(升序排序)返回有序集合成员。如果需要按照逆字典顺序排序,请使用zrevrangebylex。
- zrevrangebylex SomervilleSquares + –
1) “porter” 2) “magoun” 3) “ball” 4) “assembly” 5) “Union” 6) “Inman” 7) “Davis”
由于zrangebylex仅用于具有相同分数的有序集合,因此不接受WITHSCORES选项。然而,它接受LIMIT选项。
获取有关排序集合的信息
要找出给定排序集合中有多少个成员(换句话说,确定它的基数),请使用zcard命令。以下示例显示了在本指南的第一部分中的faveGuitarists键中有多少个成员。
- zcard faveGuitarists
(integer) 9
ZCOUNT命令可以告诉您在给定的有序集合中,有多少个元素的分数落在某个指定范围内。关键字后面的第一个数是范围的起始值,第二个数是范围的结束值。
- zcount faveGuitarists 3 8
(integer) 4
zscore函数输出一个已排序集合中指定成员的分数。
- zscore faveGuitarists “Bola Sete”
“3”
如果指定的成员或键不存在,zscore将返回(nil)。
zrank和zscore类似,但不是返回给定成员的分数,而是返回其排名。在Redis中,排名是有序集合成员的从零开始的索引,根据其分数进行排序。例如,“Joe Pass”的分数为1,但因为这是键中任何成员的最低分数,它的排名为0。
- zrank faveGuitarists “Joe Pass”
(integer) 0
还有一个Redis命令叫做zrevrank,它的功能和zrank相同,只是将集合中的成员的排名进行了反转。在下面的示例中,成员“Joe Pass”的得分最低,因此其反转排名最高。
- zrevrank faveGuitarists “Joe Pass”
(integer) 8
会员的分数和排名之间的唯一关系是他们的分数与其他成员的分数相比。如果两个相邻会员之间存在分数差距,这不会反映在他们的排名上。请注意,如果两个会员的分数相同,按字母顺序排列先的会员将获得较低的排名。
与zscore类似,如果键或成员不存在,zrank和zrevrank将返回(nil)。
zlexcount可以告诉您在字典范围内有多少个成员在一个有序集合中。以下示例使用了前一节中的SomervilleSquares有序集合。
- zlexcount SomervilleSquares [M [t
(integer) 5
这个命令的语法和 zrangebylex 命令相同,所以请参考前一部分中如何定义字符串范围的详细信息。
将成员从已排序集合中移除
ZREM命令可以从有序集合中删除一个或多个成员。
- zrem faveGuitarists “Doug Martsch” “Bola Sete”
ZREM将返回一个整数,表示从有序集合中删除了多少个成员。
(integer) 2
有三个Redis命令可以根据范围删除有序集合的成员。例如,如果有序集合中的每个成员具有相同的分数,可以使用zremrangebylex根据字典范围删除成员。该命令使用与zrangebylex相同的语法。以下示例将从前一节创建的SomervilleSquares键中删除以大写字母开头的每个成员。
- zremrangebylex SomervilleSquares [A [Z
zremrangebylex函数会返回一个整数,表示它删除的成员数量。
(integer) 3
您还可以使用zremrangebyscore命令基于分数范围删除成员,它使用与zrangebyscore命令相同的语法。以下示例将删除faveGuitarists中得分为4、5或6的所有成员。
- zremrangebyscore faveGuitarists 4 6
(integer) 1
您可以使用zremrangebyrank命令根据排名范围从集合中移除成员,该命令使用与zrangebyrank相同的语法。以下命令将移除有序集合中排名最低的三个成员,其排名由基于零索引的范围定义。
- zremrangebyrank faveGuitarists 0 2
(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。
(integer) 1
请注意,如果目标键已经存在,zinterstore 将会覆盖其内容。
zunionstore会创建一个新的有序集合,其中包含传递给它的每个键的成员。该命令使用与zinterstore相同的语法,并需要一个目标键的名称,传递给命令的键的数量和键的名称。
- zunionstore SuperGroup 2 NewKids Nsync
和zinterstore一样,zunionstore也会返回一个整数,表示存储在目标键中的元素数量。尽管两个原始排序集合都有五个成员,但由于排序集合不能有重复成员,并且每个键都有一个名为“Joey”的成员,所以最终返回的整数将是9。
(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。
聚合函数有三个子选项。其中之一是SUM,它通过将合并集合中匹配成员的分数相加来实现zinterstore和zunionstore的默认行为。
如果你在两个共享一个成员的有序集合上运行zinterstore或zunionstore操作,但这个成员在每个集合中的分数不同,你可以使用MIN子选项强制操作在新集合中分配两个分数中较低的那个分数。
- zinterstore BoyBandsWeightedMin 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MIN
因为这两个排序集合只有一个匹配成员有相同的分数(3),所以这个命令将创建一个新的集合,其中包含具有两个加权分数中较低的那个成员。
- zscore BoyBandsWeightedMin “Joey”
“9”
同样,AGGREGATE可以通过MAX选项强制zinterstore或zunionstore将较高的两个分数进行赋值。
- zinterstore BoyBandsWeightedMax 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MAX
这个命令会创建一个新的集合,其中只包含一个成员”Joey”,他的权重分数为两个分数中较高的一个。
- zscore BoyBandsWeightedMax “Joey”
“21”
在分析成员数据之前,将权重视为一种临时操控成员得分的方法是有帮助的。同样地,将聚合选项视为一种控制成员得分如何加入新数据集的方式也是有帮助的。
结论
这个指南详细介绍了在Redis中用于创建和管理有序集合的一些命令。如果在这个指南中还有其他相关命令、参数或程序,你想了解的话,请在评论中提问或提出建议。
有关Redis命令的更多信息,请查看我们关于如何管理Redis数据库的教程系列。