文章目录
[SINTER 与 SINTERSTORE](#SINTER 与 SINTERSTORE)
[SUNION 与 SUNIONSTORE](#SUNION 与 SUNIONSTORE)
[SDIFF 与 SDIFFSTORE](#SDIFF 与 SDIFFSTORE)
[二、Zset 相关命令操作](#二、Zset 相关命令操作)
[ZPOPMIN 与 BZPOPMIN](#ZPOPMIN 与 BZPOPMIN)
[ZRANK 与 ZREVRANK](#ZRANK 与 ZREVRANK)
[ZINTERSTORE 与 ZUNIONSTORE](#ZINTERSTORE 与 ZUNIONSTORE)
🙋♂️ 作者:@Ggggggtm 🙋♂️
👀 专栏:Redis 👀
💥 标题:Redis常用命令------Set、Zset篇💥
❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️
Redis 中的 Set 数据类型是一种无序且不允许重复元素的集合数据结构 。⼀个集合中最多可以存储2^32 - 1个元素。Redis 除了支持集合内的增删查改操作,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多问题。Zset是一个有序且不允许重复元素的集合,每个元素都关联一个分数(score),用于对元素进行排序 。有序集合相对于字符串、列表、哈希、集合来说会有⼀些陌生。它保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关联,着使得有序集合中的元素是可以维护有序性的,但这个有序不是用下标作为排序依据,而是用这个分数。
本篇文章就是对 Set 和 Zset 的相关操作和命令进行详解,希望会对你有所帮助!
一、Set相关命令操作
SADD
sadd命令是将⼀个或者多个元素添加到 set 中。注意,重复的元素无法添加到 set 中。语法:
cppSADD key member [member...]
参数说明:
key
:指定要操作的集合的键。member
:要添加到集合中的一个或多个元素。返回值:
- 成功添加到集合中的新元素数量。如果要添加的元素已经在集合中存在,则不会被再次添加,也不会被计算在新元素数量中。
具体可参考如下实例:
SMEMBERS
在 Redis 中,SMEMBERS命令用于返回集合中的所有成员。语法:
cppSMEMBERS key
参数:
key
:指定要获取成员的集合的键。返回值:
- 一个包含集合中所有成员的列表。
具体实例如下:
SISMEMBER
在 Redis 中,SISMEMBER命令用于判断一个元素是否是集合的成员。语法:
cppSISMEMBER key member
参数:
key
:集合的键。member
:要检查的元素。返回值:
- 如果元素是集合的成员,返回 1。
- 如果元素不是集合的成员,或集合键不存在,返回 0。
具体实例如下:
SCARD
在 Redis 中,SCARD命令用于返回集合中元素的数量。语法:
cppSCARD key
参数:
key
:集合的键。返回值:
- 集合的数量。当集合
key
不存在时,返回0
。具体如下:
SPOP
在 Redis 中,SPOP命令用于随机地从集合中移除并返回一个元素。语法:
cppSPOP key [count]
参数:
key
:指定要操作的集合的键。- count : 是可选项,表明要删除元素的个数。
返回值:
- 被移除并返回的元素。如果集合为空或键不存在,则返回
nil
。为什么是随机删除一个元素呢?根本原因就是set是一个无序集合。官方文档也说明的该操作删除的时候是随机的,采用了生成随机数的方式进行返回。具体实例如下:
SMOVE
在Redis 中,SMOVE 命令用于将指定成员member 元素从源集合source移动到目标集合destination 。语法:
cppSMOVE source destination member
参数:
source
:源集合的键。destination
:目标集合的键。member
:要移动的元素。返回值:
- 如果成员元素被成功移除,返回1。
- 如果成员元素不是源集合的成员,并且没有任何操作对目标集合执行,那么返回0。
具体可看如下实例:
如果我给key里再添加一个1,再次把这个1移动给key2,结果会怎么样呢?如下图:
通过上图可以发现,针对上述的情况, smove不会视为出错!也会按照 删除 -- 插入 进行执行。
我们再来看一下种错误的实例:
SREM
在 Redis 中,
SREM
命令用于从集合中移除一个或多个元素。语法:
cppSREM key member [member...]
参数:
key
:集合的键。member
:要从集合中移除的一个或多个元素。返回值:
- 被成功移除的元素数量。
具体如下实例:
SINTER 与 SINTERSTORE
在 Redis 中,SINTER命令用于返回给定的多个集合的交集。语法
cppSINTER key1 key2 [key3...]
参数:
key1
、key2
等:要计算交集的集合的键。返回值:
- 一个包含所有给定集合的交集元素的集合。
具体实例如下:
往往我们需要把求出的交集再次存储到另一个集合当中,这时我们就可以用到sinterstore命令。语法:
cppSINTERSTORE destination key1 key2...
其中 destination 就是我们要把结果所存储的集合当中。返回值即为交集元素的个数。具体示例如下:
SUNION 与 SUNIONSTORE
在 Redis 中,SUNION和SUNIONSTORE 命令用于处理集合操作,它们的作用是对多个集合进行并集运算。SUNION命令用于返回多个集合的并集。它接受多个集合键作为参数,并返回一个包含所有集合元素的新集合。如果某个集合不存在,则将其视为空集。SUNION命令不会修改原始集合,只是返回并集结果。
SUNIONSTORE 命令与SUNION命令类似,但它会将并集结果存储在指定的目标集合中。如果目标集合已经存在,它将被覆盖。SUNIONSTORE 命令返回并集结果集中的元素数量。
SUNION 与 SUNIONSTORE 与 SINTER 与 SINTERSTORE 语法和返回值是相似的,这里就不在过多解释。我们直接看SUNION实例:
再看SUNIONSTORE实例:
SDIFF 与 SDIFFSTORE
SDIFF 使用来求多个集合的差集的。而SDIFFSTORE就是可以将求出的差集结果存储到新的集合当中。与上述的求交集或并集命令相似。直接看SDIFF实例:
把求交集的结果存储起来用命令SDIFFSTORE,具体如下:
求集合的交集,并集和差集的规则都是数学已经定义好的,具体也可参考下图:
Set命令小结
下图即为对上述命令的总结,可根据不同的场景和需求进行选择使用。
二、Zset 相关命令操作
我们先来举个例子理解一下有序集合Zset。现在有一个场景是我们需要对三国里的英雄的战力做一个排序,但是集合只能添加元素,是无序的。此时我们需要对元素新增一个分数,来标示该元素。从而可以根据元素的分数进行排序。具体如下:
有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利⽤有序集合,可 以帮助我们在实际开发中解决很多问题。
注意:有序集合中的元素是不能重复的,但分数允许重复。类比于一次考试之后,每个人一定有一个唯一的分数,但分数允许相同 。
下面我们可以来对比一下列表(List)、集合(Set)、有序集合(Zset)的异同点:
ZADD
在 Redis 中, ZADD 命令用于向有序集合(Sorted Set)中添加一个或多个成员,或者更新已存在成员的分数(score)。语法:
cppZADD key score member [score member...]
但是ZADD种还有很多选项,具体到选项的语法如下:
cppZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]
以下对ZADD详细解释:
key
:有序集合的键。score
:成员的分数,必须是一个浮点数或整数。member
:要添加或更新的成员。NX
:只在元素不存在时添加。如果元素已经存在,则不执行更新操作。XX
:只在元素已经存在时更新。如果元素不存在,则不执行添加操作。GT
:只有在新分数大于现有分数时才更新。如果新分数小于或等于现有分数,则不执行更新操作。LT
:只有在新分数小于现有分数时才更新。如果新分数大于或等于现有分数,则不执行更新操作。CH
:返回更改的元素数量,而不仅仅是添加的新元素数量。INCR
:将给定的分数增量添加到现有成员的分数上。如果成员不存在,则将其添加,并将给定的增量作为初始分数。SADD中的 member 和 score 称为是一个"pair",这个东西类似于C++里谈到的std:pair。不要把member和score理解成"键值对"(key - value pair)。键值对中,是有明确的"角色区分"的。谁是键,谁是值,是明确的。一定是根据键->值。对于有序集合来说,是既可以通过member找到对应的score,又可以通过score找到匹配的member。所以添加的时候,既要添加元素,又要添加分数。
下面我们看集合实例:
之前Hash, Set, List很多时候,添加一个元素都是O(1)的时间复杂。此处Zset则是 log(N)。由于zset是有序结构,要求新增的元素,要放到合适的位置上(找位置)。当然之所以是log(N) 不是N,也是充分的利用了有序这样的特点(当然, zset 内部的数据结构,主要是跳表)。
zrange命令后续会讲解。带选项的大家可以自己练习一下。
ZCARD
在 Redis 中,ZCARD 命令用于获取有序集合(Sorted Set)中的成员数量。语法:
cppZCARD key
参数:
key
:有序集合的键。返回值:
- 一个整数,表示有序集合中成员的数量。如果给定的键不存在,则返回
0
。具体如下:
ZCOUNT
在 Redis 中,ZCOUNT 命令用于计算有序集合中指定分数范围内的成员数量。语法:
cppZCOUNT key min max
参数:
key
:有序集合的键。min
:分数范围的下限(包含),可以通过 ( 排除。max
:分数范围的上限(包含),可以通过 ( 排除。返回值:
- 一个整数,表示分数在指定范围内的成员数量。
具体实例如下:
ZRANGE
在 Redis 中,ZRANGE 命令用于返回有序集合中指定索引范围内的元素,返回的元素顺序是按照分数的由低到高。语法:
cppZRANGE key start stop [WITHSCORES]
参数:
key
:有序集合的键。start
:索引的起始位置,索引从 0 开始,支持负数,表示从尾部开始计算,例如 -1 表示最后一个元素。stop
:索引的结束位置,索引从 0 开始,支持负数,表示从尾部开始计算,例如 -1 表示最后一个元素。WITHSCORES
(可选):如果指定该参数,会同时返回成员的分数。返回值:
- 一个列表,包含指定索引范围内的成员。如果指定了
WITHSCORES
,则列表中的元素将是成员和其分数组成的元组。上述我们也用到了zrange。再看一下实例:
ZREVRANGE
在 Redis 中,ZREVRANGE 命令用于返回有序集合中指定索引范围内的成员,但是排序顺序是按照分数从高到低。语法:
cppZREVRANGE key start stop [WITHSCORES]
参数:
key
:有序集合的键。start
:索引的起始位置,索引从 0 开始,支持负数,表示从尾部开始计算,例如 -1 表示最后一个元素。stop
:索引的结束位置,索引从 0 开始,支持负数,表示从尾部开始计算,例如 -1 表示最后一个元素。WITHSCORES
(可选):如果指定该参数,会同时返回成员的分数。返回值:
- 一个列表,包含指定索引范围内按照分数从高到低排序的成员。如果指定了
WITHSCORES
,则列表中的元素将是成员和其分数组成的元组。具体实例如下:
ZPOPMAX
ZPOPMAX命令用于从有序集合中删除并返回 count 个具有最高得分的成员。如果没有指定count,默认值为 1。如果count大于有序集合的基数,不会产生错误。语法:
cppZPOPMAX key [count]
其中,
key
是有序集合的键,count
是要删除的成员数量(可选)。返回值是一个列表,其中包含被删除的成员和它们的分数。具体如下:
如果存在多个元素分数相同,同时为最大值zpopmax删的时候,仍然只删除其中一个元素!分数虽然是主要因素,但如果分数相同会按照member字符串的字典序决定先后!删除的时间复杂度为O(log(N)*M),其中M是指count要删除的元素个数,N是有序集合的元素个数。此处删除的是最大值!有序集合最大值就相当于最后一个元素(尾删)。既然是尾删,为什么我们不把这个最后一个元素的位置特殊记录下来~~后续删除不就可以O(1)了嘛?省去了查找的过程。但是很遗憾,目前redis 并没有这么做。事实上redis 的源码中,针对有序集合,确实是记录了尾部这样的特定位置。但是在实际删除的时候,并没有用上这个特性,而是直接调用了一个"通用的删除函数"(给定一个member的值,进行查找找到位置之后再删除)。
BZPOPMAX
BZPOPMAX是有序集合命令ZPOPMAX带有阻塞功能的版本。它会从有序集合中删除并返回最多count个具有最高得分的成员。如果没有指定count,默认值为 1。语法:
cppBZPOPMAX key (key...) timeout
其中,key是有序集合的键,timeout可以理解为客户端被阻塞的最大秒数值,0 表示永久阻塞。在参数中的所有有序集合均为空的情况下,阻塞连接。参数中包含多个有序集合时,按照参数中key的顺序,返回第一个非空key中分数最大的成员和对应的分数。返回值是一个列表,其中包含被删除的成员和它们的分数。
咱们这里的"有序集合"也可以视为是一个"优先级队列"。有的时候,也需要一个带有"阻塞功能"的优先级队列。每个key都是一个有序集合。阻塞也是在有序集合为空的时候触发阻塞,阻塞到有其他客户端插入元素。timeout表示超时时间,单位是s,支持小数形式。写作0.1就是100ms 。具体可看如下实例:
如果有序集合中已经有了元素了,直接就能返回,不会阻塞了。BZPOPMAX删除的时间复杂度为O(log(N))。如果当前BZPOPMAX同时监听了多个key,假设key是M个,此时时间复杂度是O(log(N)* M)?实际上不是的。啥时候*M?每个这样的key 上面都删除一次元素。而BZPOPMAX是从这若干个key 中只删除一次!
ZPOPMIN 与 BZPOPMIN
ZPOPMIN 与 BZPOPMIN 和 ZPOPMAX 与 BZPOPMAX 的语法和用法完全相同,只不过ZPOPMIN 与 BZPOPMIN是用来删除最小值的。
ZRANK 与 ZREVRANK
在 Redis 中,ZRANK 命令用于返回有序集合中指定成员的索引。索引按照分数升序排列(分数小的成员索引值小)。语法:
cppZRANK key member
参数:
key
:有序集合的键。member
:要获取索引的成员。返回值:
- 如果成员存在于有序集合中,返回成员的索引值(从 0 开始)。
- 如果成员不存在于有序集合中,返回
nil
。具体实例如下:
时间复杂度O(logN)。zcount在计算的时候,就是先根据分数找到元素,再根据元素获取到排名,再把排名一减,得到了元素个数。zrank得到的下标,是从前往后算的(升序)。
ZREVRANK很明显,获取到的序集合中指定成员的索引。索引按照分数降序排列(分数小的成员索引值大)。这里就不再过对举例,与ZRANK语法和用法相同。
ZSCORE
ZSCORE命令用于返回有序集合中指定成员的分数值。如果成员元素不是有序集key的成员,或key不存在,返回nil。语法:
cppZSCORE key member
时间复杂度:O(1)。前面根据member找元素都是logN。这里也是要先找元素呀。此处相当于redis 对于这样的查询操作做了特殊优化,付出了额外的空间代价针对这里进行了优化到O(1)实现。其中,key是有序集合的键,member是要获取分数的成员。具体如下:
ZREM
在 Redis 中,ZREM命令用于从有序集合中移除一个或多个成员。语法:
cppZREM key member [member...]
参数:
key
:有序集合的键。member
:要移除的一个或多个成员。返回值:
- 被成功移除的成员数量。
时间复杂度为O(logN*M)。M为参数中member的个数,N是整个有序集合中元素个数。具体如下:
ZREMRANGEBYRANK
在 Redis 中,ZREMRANGEBYRANK 命令用于移除有序集合中指定排名区间内的所有成员。语法:
cppZREMRANGEBYRANK key start stop
参数:
key
:有序集合的键。start
:排名区间的起始索引(包含),索引从 0 开始。stop
:排名区间的结束索引(包含),索引从 0 开始。返回值:被移除的成员数量。具体如下:
ZREMRANGEBYSCORE
在 Redis 中,ZREMRANGEBYSCORE 命令用于移除有序集合中,指定分数范围内的所有成员。语法:
cppZREMRANGEBYSCORE key min max
参数:
key
:有序集合的键。min
:分数范围的下限(包含)。max
:分数范围的上限(包含)。返回值:被移除成员的数量。具体如下:
ZINCRBY
在 Redis 中,ZINCRBY命令用于为有序集合中指定的成员增加指定的分数。语法:
cppZINCRBY key increment member
参数:
key
:有序集合的键。increment
:要增加的分数值,可以是正数或负数。member
:要操作的成员。返回值:
- 成员增加分数后的新分数值,以字符串形式返回。
具体如下:
不光会修改分数内容,也能同时移动元素位置,保持整个有序集合仍然是升序的。
ZINTERSTORE 与 ZUNIONSTORE
Set 求交集,并集,差集的命令:sinter,sunion, sdiff。那Zset呢?是不是:zinter, zunion, zdiff呢?这几个命令是从 Redis 6.2开始支持的。之前的版本用的是zinterstore交集,结果保存到另一个key 中和zunionstore并集,结果保存到另一个key 中。那我们来看一下zinterstore。
ZINTERSTORE命令用于计算给定的一个或多个有序集的交集,并将结果存储在指定的目标有序集中。该命令的语法如下:
cppZINTERSTORE destination numkeys key [key...] [WEIGHTS weight [weight...]] [AGGREGATE SUM|MIN|MAX]
以下是对各参数的解释:
destination
:指定结果集保存的有序集的键。numkeys
:指定参与交集运算的有序集的数量。key[key...]
:参与交集运算的有序集的键。WEIGHTS weight[weight...]
(可选):为每个参与交集运算的有序集指定一个权重。AGGREGATE SUM|MIN|MAX
(可选):指定结果集中元素的分数计算方式,可选的值为SUM
(默认,求和)、MIN
(取最小值)、MAX
(取最大值)。如果目标有序集已经存在,ZINTERSTORE命令将覆盖其内容。在默认情况下,结果集中元素的分数是其在所有参与交集运算的有序集中的分数之和。具体如下:
ZUNIONSTORE 与 ZINTERSTORE 用法和语法基本一致,不在做过对解释。
Zset命令小结
下图是Zset有序集合的命令小结,可根据不同场景进行选择。