Redis数据结构之有序集合
有序集合
Redis的有序集合(sorted set)同时具有“有序”和“集合”两种性质,这种数据结构中的每个元素都由一个成员和一个与成员相关联的分值组成,其中成员以字符串方式存储,而分数则以64位双精度浮点数格式存储。
下图展示了有序集合的存储结构:
与集合一样,有序集合中的每个成员都是独一无二的,同一个有序集合中不会出现重复的成员。与此同时,有序集合的成员将按照各自的分值大小进行排序。有序集合的分值除了可以是数字之外,还可以是字符串 **"+inf"**或者 “-inf”,这两个特殊值分别表示 无穷大 和 无穷小。
虽然成员不能重复,但是成员对应的分数却不受这一限制。
有序集合命令速查表
命令 | 用法及参数 | 说明 |
---|---|---|
ZADD | ZADD sorted_set [XX | NX] [CH] socre member [score member ...] | 添加一个或多个成员 |
ZREM | ZREM sorted_set member [member ...] | 移除一个或多个成员 |
ZSCORE | ZSCORE sorted_set member | 获取与给定成员相关联的分值 |
ZINCRBY | ZINCRBY sorted_set increment member | 对指定成员的分值执行加法操作 |
ZCARD | ZCARD sorted_set | 获取有序集合的大小 |
ZRANK | ZRANK sorted_set member | 获取给定成员在有序集合中的升序排名 |
ZREVRANK | ZREVRANK sorted_set member | 获取给定成员在有序集合中的降序排名 |
ZRANGE | ZRANGE sorted_set start end [WITHSCORES] | 以升序排列方式获取指定范围内的成员 |
ZREVRANGE | ZREVRANGE sorted_set start end [WITHSCORES] | 以降序排列方式获取指定范围内的成员 |
ZRANGEBYSCORE | ZRANGEBYSCORE sorted_set min max [WITHSCORES] | 以升序方式获取分值介于min和max之间的成员 |
ZREVRANGEBYSCORE | ZREVRANGEBYSCORE sorted_set max min [WITHSCORES] | 以降序方式获取分值介于max和min之间的成员 |
ZCOUNT | ZCOUNT sorted_set min max | 获取指定分值范围内的成员数量 |
ZREMRANGEBYRANK | ZREMRANGEBYRANK sorted_set start end | 从升序排列的有序集合中移除位于指定排名范围内的成员 |
ZREMRANGEBYSCORE | ZREMRANGEBYSCORE sorted_set min max | 从升序有序集合中移除指定分值范围内的成员 |
ZUNIONSTORE | ZUNIONSTORE destination numbers sorted_set [sorted_set ...] | 有序集合的并集运算 |
ZINSERTSTORE | ZINSERTSTORE destination numbers sorted_set [sorted_set ...] | 有序集合的交集运算 |
ZRANGEBYLEX | ZRANGEBYLEX sorted_set min max | 可以从按字典升序排序的有序集合中返回指定范围的成员 |
ZREVRANGEBYLEX | ZREVRANGEBYLEX sorted_set max min | 可以从按字典降序排序的有序集合中返回指定范围内的成员 |
ZLEXCOUNT | ZLEXCOUNT sorted_set min max | 获取按字典排序的有序集合指定范围内的成员数量 |
ZREMRANGEBYLEX | ZREMRANGEBYLEX sorted_set min max | 移除按字典排序的有序集合指定范围内的成员 |
ZPOPMAX | ZPOPMAX sorted_set [count] | 移除有序集合中分值最大的N个成员 |
ZPOPMIN | ZPOPMIN sorted_set [count] | 移除有序集合中分值最小的N个成员 |
BZPOPMAX | BZPOPMAX sorted_set [sorted_set] timeout | ZPOPMAX命令的阻塞版本 |
BZPOPMIN | BZPOPMIN sorted_set [sorted_set ...] timeout | ZPOPMIN命令的阻塞版本 |
命令详解
ZADD命令
使用ZADD命令可以向有序集合添加一个或多个成员:
ZADD sorted_set socre member [score member ...]
默认情况下,ZADD命令将返回成功添加的新成员数量作为返回值。
127.0.0.1:6379> ZADD salary 3500 "peter" 4000 "jack" 2000 "tom" 5500 "mary"
(integer) 4
更新已有成员的分值
ZADD命令除了可以向有序集合添加新成员以外,还可以对有序集合中已存在的成员的分值进行更新:在默认情况下,如果用户在执行ZADD命令时,给定成员已经存在,并且给定的分值和现有成员的分值不相同,那么ZADD命令将使用给定的新分值去覆盖现有的旧分值。
127.0.0.1:6379> ZADD salary 5000 "tom"
(integer) 0 -- 因为这是一次更新操作,没有添加任何新成员,所以返回0
指定要执行的操作
从Redis 3.0.2版本开始,Redis允许用户在执行ZADD命令时,通过使用可选的XX选项或者NX选项来显示地指示命令执行更新操作或者执行添加操作:
ZADD sorted_set [XX | NX] score member [score member ...]
这两个选项的功能如下:
- 在给定XX选项的情况下,ZADD命令只会对给定成员当中已存在于有序集合的成员进行更新,而那些不存在于有序集合的成员则会被忽略。
- 在给定NX选项的情况下,ZADD命令只会把给定成员当中不存在于有序集合的成员添加到有序集合,而存在于有序集合的成员则会被忽略。
返回被修改成员的数量
在默认情况下,ZADD命令会返回添加成员的数量,但是从 Redis 3.0.2版本开始,用户可以通过给定CH选项,让ZADD命令返回被修改(changed)成员的数量作为返回值:
ZADD sorted_set [CH] score number [score number ...]
其中 **“被修改成员”**指的是新添加到有序集合的成员,以及分值被修改的成员。
127.0.0.1:6379> ZADD salary CH 3500 "peter" 4000 "bob" 9000 "david"
(integer) 2
复杂度:
O
(
M
∗
l
o
g
(
N
)
)
O(M*log(N))
O(M∗log(N)),其中
M
M
M为给定成员的数量,而
N
N
N则为有序集合的成员数量。
版本要求:不带任何选项的ZADD命令从 Redis 1.2.0版本开始可用,带有 NX、XX、CH等选项的ZADD命令从Redis 3.0.2版本开始可用。Redis 2.4.0以前ZADD命令只允许一次添加一个成员,而Redis 2.4.0及以上版本支持一次添加多个成员。
ZREM命令
使用ZREM命令可以从有序集合中移除一个或多个成员及其关联的分值:
ZREM sorted_set member [member ...]
成功移除后将返回被移除成员的数量。
127.0.0.1:6379> ZREM salary "peter"
(integer) 1
如果用户给定的成员不存在,那么ZREM将自动忽略该成员。
复杂度:
O
(
M
∗
l
o
g
(
N
)
)
O(M*log(N))
O(M∗log(N)),其中
M
M
M为给定的成员数量,
N
N
N为有序集合包含的成员数量。
版本要求:ZREM命令从Redis 1.2.0版本开始用,Redis 2.4.0版本及以上支持一次移除多个成员。
ZSCORE命令
通过使用ZSCORE命令,可以获取与给定成员相关联的分值:
ZSCORE sorted_set member
127.0.0.1:6379> ZSCORE salary "jack"
"4000"
如果给定的有序集合或成员不存在,则返回空值。
复杂度:
O
(
1
)
O(1)
O(1)
版本要求:ZSCORE命令从Redis 1.2.0版本可用。
ZINCRBY命令
通过使用ZINCRBY命令,可以对指定成员的分值执行加法操作:
ZINCRBY sorted_set increment member
执行成功后,返回当前成员对应的分值。
127.0.0.1:6379> ZINCRBY salary 1000 "jack"
"5000"
如果传入的增量为负数,则可以实现减法操作:
127.0.0.1:6379> ZINCRBY salary -1000 "peter"
"2000"
如果给定的有序集合或成员不存在,那么ZINCRBY命令直接把给定的成员添加到有序集合中,并把给定的增量设置为该成员的分值:
127.0.0.1:6379> ZINCRBY salary 1500 "lily"
"1500"
复杂度:
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N)),其中
N
N
N为有序集合包含的成员数量。
版本要求:ZINCRBY命令从Redis 1.2.0版本开始可用。
ZCARD命令
使用ZCARD命令可以获取有序集合的大小,即有序集合中包含的成员数量:
ZCARD sorted_set
127.0.0.1:6379> ZCARD salary
(integer) 4
复杂度:
O
(
1
)
O(1)
O(1)
版本要求:ZCARD命令从Redis 1.2.0版本开始可用。
ZRANK、ZREVRANK命令
通过ZRANK命令和ZREVRANK命令可以获取指定成员在有序集合中的排名:
ZRANK sorted_set
ZREVRANK sorted_set
其中ZRANK命令返回的是成员的升序排名,即成员在按照分值从小到大进行排序时的排名,而ZREVRANK命令返回的是成员的降序排名,即成员在按照分值的从大到小的排序时的排名。
127.0.0.1:6379> ZRANK salary "peter"
(integer) 0
127.0.0.1:6379> ZRANK salary "tom"
(integer) 3
127.0.0.1:6379> ZREVRANK salary "peter"
(integer) 4
如果给定的有序集合或成员不存在,那么两个命令都会返回空值。
复杂度:
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N)),其中
N
N
N为有序集合的成员数量。
版本要求:ZRANK命令和ZREVRANK命令从Redis 2.0.0版本开始可用。
ZRANGE、ZREVRANGE命令
使用ZRANGE命令和ZREVRANGE命令,可以以升序或降序的排列方式,从有序集合中获取指定索引范围内的成员:
ZRANGE sorted_set start end
ZREVRANGE sorted_set start end
其中ZRANGE命令用于获取按照分值从小到大升序排列的成员,而ZREVRANGE命令则用于获取从大到小降序排列的成员。命令中的start索引和end索引指定的是闭区间索引范围,也就是说包含了两个索引位置上的成员。
127.0.0.1:6379> ZRANGE salary 0 3
1) "peter"
2) "bob"
3) "jack"
4) "tom"
与之前介绍过的列表命令LRANGE类似,ZRANGE命令和ZREVRANGE命令除了可以接受正数索引,也可以接受负数索引:
127.0.0.1:6379> ZRANGE salary -3 -1
1) "jack"
2) "tom"
3) "mary"
获取成员及其分值
在默认情况下,ZRANGE命令和ZREVRANGE命令只返回指定索引范围内的成员,如果用户想要在获取这些成员的同时获取与之关联的分值,那么可以在使用WITHSOCRES选项:
ZRANGE sorted_set start end [WITHSCORES]
ZREVRANGE sorted_set start end [WITHSCORES]
127.0.0.1:6379> ZRANGE salary 0 3 WITHSCORES
1) "peter"
2) "3500"
3) "bob"
4) "3800"
5) "jack"
6) "4500"
如果给定的有序集合不存在,那么将返回一个空列表。
复杂度:
O
(
l
o
g
(
N
)
+
M
)
O(log(N)+M)
O(log(N)+M),其中
N
N
N为有序集合的成员数量,而
M
M
M为命令返回的成员数量。
版本要求:ZRANGE命令和ZREVRANGE命令从Redis 1.2.0版本开始可用。
ZRANGEBYSCORE、ZREVRANGEBYSCORE命令
通过使用ZRANGEBYSCORE命令或者ZREVRANGEBYSCORE命令,可以以升序或降序的方式获取有序集合中分值介于指定范围内的成员:
ZRANGEBYSCORE sorted_set min max
ZREVRANGEBYSCORE sorted_set max min
命令的min参数和max参数分别用于指定用户想要获取的成员最小分值和最大分值。
注意: ZRANGEBYSCORE命令和ZREVRANGEBYSCORE命令接受的min和max参数的顺序正好相反:ZRANGEBYSCORE命令先接受min参数,然后再接受max参数,而ZREVRANGEBYSCORE命令刚好相反。
与ZRANGE命令类似,如果想要同时获取成员对应的分值,则需要使用WITHSCORES选项:
ZRANGEBYSCORE sorted_set min max [WITHSCORES]
ZREVRANGEBYSCORE sorted_set max min [WITHSCORES]
限制命令返回的成员数量
在默认情况下,ZRANGEBYSCORE命令或者ZREVRANGEBYSCORE命令会直接返回给定分值范围内的所有成员,但是如果范围内的成员数量较多,或者我们只需要一部分成员,那么可以使用可选的LIMIT选项来限制命令返回的成员数量:
ZRANGEBYSCORE sored_set min max [WITHSCORES] [LIMIT offset count]
ZREVRANGESCORE sorted_set max min [WITHSCORES] [LIMIT offset count]
LIMIT选项接受offset和count两个参数作为输入,其中offset参数用于指定命令在返回结果之前需要跳过的成员数量,而count参数用于指示命令最多可以返回的成员数量。
127.0.0.1:6379> ZRANGEBYSCORE salary 3000 5000 LIMIT 0 1
1) "peter"
使用开区间分值范围
在默认情况下,ZRANGEBYSCORE命令和ZREVRANGEBYSCORE命令接受的分值范围都是闭区间的,如果想要使用开区间,那么可以在给定分值范围时,在分值参数的前面加上一个单括号 “(”,如下所示:
127.0.0.1:6379> ZRANGEBYSCORE salary (3000 (5000 WITHSCORES
1) "bob"
2) "3800"
3) "jack"
4) "4500"
使用无限值作为范围
ZRANGEBYSCORE命令和ZREVRANGEBYSCORE命令的min参数和max参数除了可以是普通的分值或带有 **"("**符号的分值之外,还可以使用特殊值 **"+inf"**或者 -inf,前者用于表示 无穷大,后者表示 无穷小。
127.0.0.1:6379> ZRANGEBYSCORE salary -inf (4500 WITHSCORES -- 获取小于分值4500的成员及其分值
1) "peter"
2) "3500"
3) "bob"
4) "3800"
复杂度:
O
(
l
o
g
(
N
)
+
M
)
O(log(N)+M)
O(log(N)+M),其中
N
N
N为有序集合包含的成员数量,而
M
M
M则为命令返回的成员数量。
版本要求:ZRANGEBYSCORE命令从Redis 1.0.5版本开始可用,而ZREVRANGEBYSCORE命令从Redis 2.2.0版本开始可用。
ZCOUNT命令
通过使用ZCOUNT命令,用户可以统计出有序集合中分值介于指定范围内的成员数量:
ZCOUNT sorted_set min max
127.0.0.1:6379> ZCOUNT salary 3000 5000
(integer) 4
复杂度:
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N)),其中
N
N
N为有序集合包含的成员数量。
版本要求:ZCOUNT命令从Redis 2.0.0版本开始可用。
ZREMRANGEBYRANK命令
ZREMRANGEBYRANK命令可以从升序排列的有序集合中移除位于指定排名范围内的成员,然后返回被移除成员的数量:
ZREMRANGEBYRANK sorted_set start end
与Redis其他范围命令一样,该命令的范围也是闭区间的,也支持负数排名区间。
复杂度:
(
l
o
g
(
N
)
+
M
)
(log(N)+M)
(log(N)+M),其中
N
N
N为有序集合中的成员数量,而
M
M
M为被移除的成员数量。
版本要求:该命令从Redis 2.0.0版本开始可用。
ZREMRANGEBYSCORE命令
ZREMRANGEBYSCORE命令可以从升序有序集合中移除指定分值范围内的成员,并返回被移除成员的数量:
ZREMRANGEBYSCORE sorted_set min max
ZREMRANGEBYSCORE命令与ZRANGEBYSCORE命令一样,默认使用闭区间,也可以支持开区间和无限值。
复杂度:
O
(
l
o
g
(
N
)
+
M
)
O(log(N)+M)
O(log(N)+M),其中
N
N
N为有序集合中的成员数量,而
M
M
M为被移除成员的数量。
版本要求:该命令从Redis 1.2.0版本开始可用。
ZUNIONSTORE、ZINSERTSTORE命令
与集合一样,Redis也为有序集合提供了相应的并集运算命令ZUNIONSTORE和交集运算命令ZINSERTSTORE:
ZUNIONSTORE destination numbers sorted_set [sorted_set ...]
ZINSERTSTORE destination numbers sorted_set [sorted_set ...]
其中,命令的numbers参数用于指定参与计算的有序集合数量,之后的一个或多个sorted_set参数用于指定参与计算的有序集合键名,计算得出的结果会存储到destination指定的键中。
对于有序集合运算,相同成员的情况下,默认情况下分值相加。
两个命令都会返回计算结果包含的成员数量。
127.0.0.1:6379> union-result 2 sorted_set1 sorted_set2
(integer) 5
指定聚合函数
Redis为ZUNIONSTORE命令和ZINSERTSTORE命令提供了可选的AGGREGATE选项,通过这个选项,用户可以决定使用哪个聚合函数来计算结果有序集合成员的分值:
ZUNIONSTORE destination numbers sorted_set [sorted_set ...] [AGGREGATE SUM|MIN|MAX]
ZINSERTSTORE destination numbers sorted_set [sorted_set ...] [AGGREGATE SUM|MIN|MAX]
AGGREGATE选项的值可以是SUM、MIN或者MAX中的一个,作用如下表所示:
聚合函数 | 作用 |
---|---|
SUM | 把给定有序集合中所有相同成员的分值都相加起来,它们的和就是该成员在结果有序集合中的分值 |
MIN | 从给定有序集合所有相同成员的分值中选出最小的分值,并把它作为该成员在结果有序集合中的分值 |
MAX | 从给定有序集合所有相同成员的分值中选出最大的分值,并把它作为改成员在结果有序集合中的分值 |
默认情况下,如果未指定聚合函数,则默认使用SUM。
设置权重
在默认情况下,ZUNIONSTORE命令和ZINSERTSTORE命令将直接使用成员的分值去计算结果有序集合成员的分值,但是在有需要的情况下,也可以通过可选的WEIGHTS参数为各个给定有序集合的成员分值设置权重:
ZUNIONSTORE destination numbers sorted_set [sorted_set ...] [WEIGHTS weight [weight ...]]
ZINSERTSTORE destination numbers sorted_set [sorted_set ...] [WEIGHTS weight [weight ...]]
在使用WEIGHTS选项时,用户需要为每个给定的有序集合分别设置一个权重,命令会将这个权重与成员的分值相乘,得出成员的新分值,然后执行聚合运算。与此相反,如果用户在使用WEIGHTS选项时,不想改变某个成员的分值,那么只需要将那个成员的权重设置为1即可。
使用集合作为输入
ZUNIONSTORE命令和ZINSERTSTORE命令除了可以使用有序集合作为输入之外,还可以使用集合作为输入:在默认情况下,这两个命令将把给定的集合看作是所有成员的分值都为1的有序集合来进行计算。如果有需要,可以使用WEIGHTS选项来改变集合的分值。
复杂度:ZUNIONSTORE命令的复杂度为
O
(
N
∗
l
o
g
(
N
)
)
O(N*log(N))
O(N∗log(N)),其中
N
N
N为所有给定有序集合的成员总数。ZINSERTSTORE命令的复杂度为
O
(
N
∗
l
o
g
(
N
)
∗
M
)
O(N*log(N)*M)
O(N∗log(N)∗M),其中
N
N
N为所有给定有序集合中,基数最小的那个有序集合的基数,而
M
M
M则是给定的有序集合的数量。
版本要求:两个命令都是从Redis 2.0.0版本开始可用。
ZRANGEBYLEX、ZREVRANGEBYLEX命令
如果有序集合中的所有成员的分值都相同,这种情况下,之前讲述的排序命令如:ZRANGEBYSCORE、ZCOUNT和ZREMRANGEBYSCORE等,都将不再适用。
因此,Redis提供了相应的ZRANGEBYLEX、ZREVRANGEBYLEX、ZLEXCOUNT和ZREMRANGEBYLEX命令,这些命令可以分别对字典排序的有序集合执行升序或降序排练范围获取操作、统计位于字典序指定范围内的成员数量、移除字典序指定范围内的成员等操作。
ZRANGEBYLEX sorted_set min max
其中参数min和max的取值方式如下:
- 带有 “[” 符号的值表示在结果中包含与给定值具有同等字典大小的成员。
- 带有 “(” 符号的值表示在结果中不包含与给定值具有相同字典大小的成员。
- 加号 “+” 表示无穷大。
- 减号 “-” 表示无穷小。
127.0.0.1:6379> ZRANGEBYLEX words [a [b
1) "address"
2) "after"
3) "apple"
ZREVRANGEBYLEX命令的用法与ZRANGEBYLEX命令类似,不同的是参数 min 和 max正好相反:
ZREVRANGEBYLEX sorted_set max min
同样的,与有序集合其他范围命令一样,ZRANGEBYLEX命令和ZREVRANGEBYLEX命令也可以通过 LIMIT选项来限制返回成员的数量:
ZRANGEBYLEX sorted_set min max [LIMIT offset count]
ZREVRANGEBYLEX sorted_set max min [LIMIT offset count]
复杂度:两个命令的复杂度都为
O
(
l
o
g
(
N
)
+
M
)
O(log(N)+M)
O(log(N)+M),其中
N
N
N为有序集合包含的成员数量,而
M
M
M为命令返回的成员数量。
版本要求:两个命令从Redis 2.8.9版本开始可用。
ZLEXCOUNT命令
使用ZLEXCOUNT命令可以获取按字典排序的有序集合中位于指定字典范围内的成员数量:
ZLEXCOUNT sorted_set min max
其中 min 和 max参数的用法和ZRANGEBYLEX命令的一样。
复杂度:
O
(
l
o
g
(
N
)
)
O(log(N))
O(log(N)),其中
N
N
N为有序集合成员数量。
版本要求:从Redis 2.8.9开始可用。
ZREMRANGEBYLEX命令
使用ZREMRANGEBYLEX命令可以从按字典排序的有序集合中,移除指定字典范围内的成员:
ZREMRANGEBYLEX sorted_set min max
复杂度:
O
(
l
o
g
(
N
)
+
M
)
O(log(N)+M)
O(log(N)+M),其中
N
N
N为有序集合成员数量,
M
M
M为移除的成员数量。
版本要求:从Redis 2.8.9版本开始可用。
ZPOPMAX、ZPOPMIN命令
ZPOPMAX命令和ZPOPMIN命令是Redis 5.0版本新添加的命令,分别用于移除并返回有序集合中分值最大和最小的N个元素:
ZPOPMAX sorted_set [count]
ZPOPMIN sorted_set [count]
复杂度:
O
(
N
)
O(N)
O(N),其中
N
N
N为有序集合的成员数量。
版本要求:从Redis 5.0开始可用。
BZPOPMAX、BZPOPMIN命令
BZPOPMAX命令和BZPOPMIN命令分别是ZPOPMAX命令和ZPOPMIN命令的阻塞版本,这两个阻塞命令都接受任意多个有序集合和一个秒级精度的超时时限作为参数:
BZPOPMAX sorted_set [sorted_set ...] timeout
BZPOPMIN sorted_set [sorted_set ...] timeout
从遇到的第一个非空有序集合中弹出指定的元素,如果所给有序集合都为空,则阻塞执行该命令的客户端,直到遇到可以弹出的成员,或者达到超时时限。
复杂度:
O
(
N
)
O(N)
O(N),其中
N
N
N为有序集合的数量。
版本要求:从Redis 5.0版本开始可用。