(Redis基础教程之九) 如何在Redis中使用Sorted Sets
介绍Redis是一个开源的内存中键值数据存储。在Redis的排序集合类似于一个数据类型集在这两者都是串的非重复的组。不同之处在于已排序集中的每个成员都与一个分数相关联从而可以从最小分数到最大分数进行排序。与集合一样排序集合中的每个成员都必须是唯一的尽管多个成员可以共享同一分数。本教程说明了如何创建排序集检索和删除其成员以及如何从现有集合中创建新的排序集。如何使用本指南本指南以备有完整示例的备忘单形式编写。我们鼓励您跳至与您要完成的任务相关的任何部分。本指南中显示的命令已在运行Redis版本4.0.9的Ubuntu 18.04服务器上进行了测试。要设置类似的环境您可以按照我们的指南如何在Ubuntu 18.04上安装和保护Redis的步骤1进行操作。我们将通过使用Redis命令行界面运行它们来演示这些命令的行为。请注意如果您使用其他Redis界面例如Redli则某些命令的确切输出可能会有所不同。redis-cli另外您可以提供一个托管的Redis数据库实例来测试这些命令但是请注意根据数据库提供者所允许的控制级别本指南中的某些命令可能无法按所述方式工作。要配置DigitalOcean托管数据库请遵循我们的托管数据库产品文档。然后您必须安装Redli或设置TLS隧道才能通过TLS连接到托管数据库。Creating Sorted Sets and Adding Members要创建排序集请使用zadd命令。zadd接受将保留排序后的键集的键的名称作为参数后跟要添加的成员的分数以及成员本身的值。以下命令将创建一个排序的集合密钥其名称faveGuitarists为一个成员Joe Pass得分为1zadd faveGuitarists 1 Joe Passzadd将返回一个整数该整数指示成功创建排序集后将添加到排序集中的成员数。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) 8zadd可以接受以下选项您必须在密钥名称之后和第一个成员评分之前输入以下选项NX或XX这些选项具有相反的效果因此您在任何zadd操作中都只能包括其中之一NX告诉zadd不更新现有成员。使用此选项zadd将仅添加新元素。XX告诉zadd给只更新现有的元素。使用此选项zadd将永远不会添加新成员。CH通常zadd仅返回添加到排序集中的新元素的数量。但是zadd如果包含此选项将返回已_更改_元素的数量。这包括新添加的成员和分数已更改的成员。INCR这会使命令增加成员的得分值。如果该成员还不存在则该命令会将其添加到已排序的集合中并将其增量作为分数就像其原始分数是一样0。如果INCR包含则成功zadd将返回成员的新分数。请注意使用此选项时一次只能包含一个分数/成员对。无需将INCR选项传递给zadd您可以使用zincrby行为完全相同的命令。而不是给排序后的集合成员像分数那样由得分值指示的值zadd而是使该成员的得分增加该值。例如下面的命令增量构件的分数Stephen Malkmus这本来4增长5到9。zincrby faveGuitarists 5 Stephen Malkmus Output9与zadd命令INCR选项一样如果指定的成员不存在则将zincrby使用增量值作为其分数来创建它。Retrieving Members from Sorted Sets检索排序集中的成员的最基本方法是使用zrange命令。此命令接受要检索其成员的键的名称以及其中包含的成员范围作为参数。范围由两个数字定义这些数字表示从零开始的索引0表示代表排序集中的第一个成员或得分最低的成员1代表下一个依此类推。下面的示例将返回faveGuitarists上一部分中创建的排序集中的前四个成员zrange faveGuitarists 0 3 Output1) Joe Pass 2) Rosetta Tharpe 3) Bola Sete 4) Doug Martsch请注意如果传递给的排序集zrange具有两个或多个共享相同分数的元素它将按照_字典顺序_或字母顺序对这些元素进行排序。开始索引和停止索引也可以是负数-1代表最后一个成员-2代表倒数第二个依此类推zrange faveGuitarists -5 -2 Output1) Memphis Minnie 2) Elizabeth Cotten 3) Stephen Malkmus 4) Michael Houserzrange可以接受WITHSCORES参数当包含该参数时该参数还将返回成员的分数zrange faveGuitarists 5 6 WITHSCORES Output1) Elizabeth Cotten 2) 8 3) Stephen Malkmus 4) 9zrange只能以数字升序返回一系列成员。要反转它并以降序返回范围必须使用zrevrange命令。可以将此命令视为暂时反转给定排序集的顺序然后返回属于指定范围内的成员。因此使用zrevrange0将代表密钥中持有的最后一个成员1将代表倒数第二个等等zrevrange faveGuitarists 0 5 Output1) Nancy Wilson 2) Michael Houser 3) Stephen Malkmus 4) Elizabeth Cotten 5) Memphis Minnie 6) Doug Martschzrevrange也可以接受该WITHSCORES选项。您可以使用zrangebyscore命令根据其分数返回一系列成员。在下面的示例中该命令将返回faveGuitarists键中分数为2、3或4的任何成员zrangebyscore faveGuitarists 2 4 Output1) Rosetta Tharpe 2) Bola Sete 3) Doug Martsch 4) Memphis Minnie在此示例中范围是包含范围的这意味着它将返回分数为2或4的成员。您可以在范围的任一末端加上一个开放的括号(以排除该范围的任何一端。以下示例将返回分数大于或等于2但小于的每个成员4zrangebyscore faveGuitarists 2 (4 Output1) Rosetta Tharpe 2) Bola Sete 3) Doug Martsch与一样zrangezrangebyscore可以接受WITHSCORES参数。它还接受该LIMIT选项您可以使用该选项仅从zrangebyscore输出中检索元素的选择。此选项接受一个offset偏移量和一个count计数该偏移量标记该命令将返回的范围内的第一个成员该计数总共定义该命令将返回的成员数。例如以下命令将查看已faveGuitarists排序集合的前六个成员但仅从该集合中返回3个成员从该范围内的第二个成员开始由表示1zrangebyscore faveGuitarists 0 5 LIMIT 1 3 Output1) Rosetta Tharpe 2) Bola Sete 3) Doug Martsch该zrevrangebyscore命令根据成员的得分返回相反的范围。以下命令将返回分数在10到6之间的集合中的每个成员zrevrangebyscore faveGuitarists 10 6 Output1) Stephen Malkmus 2) Elizabeth Cotten与一样zrangebyscorezrevrangebyscore可以接受WITHSCORES和LIMIT选项。此外您可以在范围的两端加上开放括号来排除该范围的任何一端。有时排序集中的所有成员都具有相同的分数。在这种情况下您可以使用命令强制redis返回按_字典顺序_或字母顺序排序的元素范围zrangebylex。要尝试此命令请运行以下zadd命令以创建一个排序的集合其中每个成员具有相同的分数zadd SomervilleSquares 0 Davis 0 Inman 0 Union 0 porter 0 magoun 0 ball 0 assemblyzrangebylex后面必须跟一个键的名称一个开始间隔和一个停止间隔。开始和停止间隔必须以圆括号(或方括号开头[如下所示zrangebylex SomervilleSquares [a [z Output1) assembly 2) ball 3) magoun 4) porter请注意即使该命令查找的范围是从a到该示例也仅返回集合中八个成员中的四个z。这是因为Redis值区分大小写因此以大写字母开头的成员将从其输出中排除。要返回这些值可以运行以下命令zrangebylex SomervilleSquares [A [z Output1) Davis 2) Inman 3) Union 4) assembly 5) ball 6) magoun 7) porterzrangebylex还接受特殊字符-它们代表负无穷大而代表正无穷大。因此以下命令语法还将返回排序集中的每个成员zrangebylex SomervilleSquares - 请注意zrangebylex不能以相反的字典顺序字母升序返回排序的集合成员。为此请使用zrevrangebylexzrevrangebylex SomervilleSquares - Output1) porter 2) magoun 3) ball 4) assembly 5) Union 6) Inman 7) Davis因为它适用于每个成员都具有相同分数的排序集zrangebylex所以不接受该WITHSCORES选项。但是它确实接受该LIMIT选项。Retrieving Information about Sorted Sets要查找给定排序集中有多少个成员或者换句话说确定其基数请使用zcard命令。以下示例显示了faveGuitarists本指南第一部分中密钥中拥有多少成员zcard faveGuitarists Output(integer) 9zcount可以告诉您在给定的排序集中有多少个元素落在分数范围内。键后面的第一个数字是范围的开始第二个数字是范围的结束zcount faveGuitarists 3 8 Output(integer) 4zscore输出排序集中指定成员的分数zscore faveGuitarists Bola Sete Output3如果指定的成员或密钥都不存在zscore将返回(nil)。zrank与相似zscore但不返回给定成员的分数而是返回其排名。在Redis中_等级_是排序集中成员的从零开始的索引按其得分排序。例如Joe Pass得分为1但是由于这是键中所有成员的最低得分因此其等级为0zrank faveGuitarists Joe Pass Output(integer) 0调用了另一个Redis命令zrevrank该命令执行与相同的功能zrank但取而代之的是反转集合中成员的等级。在以下示例中该成员Joe Pass的得分最低因此其反向排名最高zrevrank faveGuitarists Joe Pass Output(integer) 8成员的分数与其等级之间的唯一关系是其分数相对于其他成员的分数所处的位置。如果两个连续成员之间存在得分差距则该得分差距不会反映在他们的排名中。请注意如果两个成员的分数相同则按字母顺序排在第一位的成员将具有较低的排名。类似于zscore如果键或成员不存在zrankzrevrank将返回(nil)。zlexcount可以告诉您在词典范围之间的排序集中有多少个成员。下面的示例使用SomervilleSquares上一节中的排序集zlexcount SomervilleSquares [M [t Output(integer) 5该命令的语法与zrangebylex命令相同因此请参见上一节以获取有关如何定义字符串范围的详细信息。Removing Members from Sorted Sets该zrem命令可以从排序集中删除一个或多个成员zrem faveGuitarists Doug Martsch Bola Setezrem将返回一个整数指示从排序集中删除了多少个成员Output(integer) 2有三个Redis命令可让您根据范围删除排序集中的成员。例如如果排序集中的每个成员都具有相同的分数则可以使用来根据词典范围删除成员zremrangebylex。此命令使用与相同的语法zrangebylex。以下示例将从SomervilleSquares上一节中创建的密钥中删除所有以大写字母开头的成员zremrangebylex SomervilleSquares [A [Zzremrangebylex将输出一个整数指示已删除的成员数Output(integer) 3您还可以zremrangebyscore使用命令使用与命令相同的语法根据分数范围删除成员zrangebyscore。以下示例将删除faveGuitarists得分为4、5或6的每个成员zremrangebyscore faveGuitarists 4 6 Output(integer) 1您可以从基于一系列与队伍的一组删除成员zremrangebyrank的命令它使用相同的语法zrangebyrank。以下命令将删除排名最低的排序集中的三个成员这些成员由一系列从零开始的索引定义zremrangebyrank faveGuitarists 0 2 Output(integer) 3请注意传递给的数字remrangebyrank也可以为负-1代表最高排名次高排名-2依此类推。Creating New Sorted Sets from Existing OnesRedis包含两个命令它们允许您比较多个排序集的成员并基于这些比较创建新的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 JCzinterstore查找两个或多个排序集它们的交集共享的成员并生成仅包含那些成员的新排序集。此命令必须依次包括相交成员将以排序集存储的目标键的名称要传递给的键的数量以及zinterstore要分析的键的名称zinterstore BoyBands 2 NewKids Nsynczinterstore将返回一个整数该整数显示存储到目标排序集中的元素数。因为NewKids和Nsync仅共享一个成员Joey所以该命令将返回1Output(integer) 1请注意如果目标键已经存在zinterstore将覆盖其内容。zunionstore将创建一个新的排序集其中包含传递给它的每个键成员。此命令使用与相同的语法zinterstore并且需要目标键的名称传递给该命令的键的数量以及键的名称zunionstore SuperGroup 2 NewKids Nsync像一样zinterstorezunionstore将返回一个整数显示存储在目标键中的元素数。即使两个原始排序集都包含五个成员但由于排序集不能包含重复成员并且每个键都有一个名为Joey的成员因此所得的整数将为9Output(integer) 9与一样zinterstorezunionstore如果目标键已经存在它将覆盖目标键的内容。为了在使用zinterstore和创建新的排序集时更好地控制成员分数zunionstore这两个命令都接受WEIGHTS和AGGREGATE选项。对于WEIGHTS该命令中包含的每个排序集此选项后均带有一个数字该数字_加权_或乘以每个成员的分数。WEIGHTS选项后的第一个数字对传递给命令的第一个键的分数加权第二个数字对第二个键的加权加权依此类推。以下示例创建一个新的排序集其中包含来自NewKids和Nsync排序集的相交键。它将NewKids密钥中的分数加权三倍并将密钥中的分数加权Nsync七倍zinterstore BoyBandsWeighted 2 NewKids Nsync WEIGHTS 3 7如果WEIGHTS选项未包括在内权重默认为1两个zinterstore和zunionstore。AGGREGATE接受三个子选项。其中的第一个通过添加组合集中匹配成员的得分来SUM实现zinterstore和zunionstore的默认行为。如果在共享一个成员的两个排序集合上运行zinterstore或zunionstore运算但是该成员在每个集合中具有不同的分数则可以使用MIN子选项强制操作在新集合中分配两个分数中的较低者。zinterstore BoyBandsWeightedMin 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MIN由于这两个排序的集合只有一个具有相同分数3的匹配成员因此此命令将创建一个新集合其成员具有两个加权分数中的较低者zscore BoyBandsWeightedMin Joey Output9同样AGGREGATE可以使用以下选项强制zinterstore或zunionstore分配两个分数中的较高者MAXzinterstore BoyBandsWeightedMax 2 NewKids Nsync WEIGHTS 3 7 AGGREGATE MAX此命令创建一个新集合其中有一个成员Joey具有两个加权得分中的较高者zscore BoyBandsWeightedMax Joey Output21将其WEIGHTS视为在分析成员之前临时操纵其分数的一种方式可能会有所帮助。同样将AGGREGATE选项视为在将成员添加到新集中之前决定如何控制其分数的一种方式也很有帮助。Conclusion本指南详细介绍了用于在Redis中创建和管理排序集的许多命令。如果您想在本指南中概述其他相关的命令参数或过程请在下面的评论中提出疑问或提出建议。有关Redis命令的更多信息请参阅关于如何管理Redis数据库的系列教程。如何在ubuntu18.04上安装和保护redis如何连接到Redis数据库如何管理Redis数据库和Keys如何在Redis中管理副本和客户端如何在Redis中管理字符串如何在Redis中管理list如何在Redis中管理Hashes如何在Redis中管理Sets如何在Redis中管理Sorted Sets如何在Redis中运行事务如何使Redis中的Key失效如何解决Redis中的故障如何从命令行更改Redis的配置Redis数据类型简介Redis 中如何使用 lua 脚本Redis 常用命令指南