Redis 数据类型之有序集合(Sorted Set)

 2016年09月03日    454     声明


  1. 有序集集合
  2. 有序集合操作命令及使用

1. 有序集集合

Redis 中的有序集合(Sorted Set)类似于集合类型,二都都是字符串的集合,都不允许重复的成员的存在。它们之间的主要区别是有序集合中的每一个成员都会有一个分数(score)与之关联,Redis 通过这个分数来对集合成员按从小到大的顺序排序。

score是Reids 对集合元素排序的一个权重依据,虽然集合元素不可重复,但score是可重复的

Redis 的有序集合类型操作效率非常高,是其它同类数据库所难以实现。在有序集合中添加、删除或更新一个元素的操作速度都非常快,其时间复杂度为集合中成员数量的对数。由于有序集合中的成员在集合中的位置是有序的,所以即使是操作集合中部的成员也会非常高效。


2. 有序集合操作命令及使用

2.1 有序集合添加、修改元素

有序集合使用ZADD命令向已经的有序集合添加新元素,或创建新的有序集合。score是有序集合排序时的权重依据,对于已存在的元素,可以使用ZINCRBY命令修改元素的权重值。

2.1.1 ZADD - 添加元素

ZADD key score member [[score member] [score member] ...]

将一个或多个元素及其score值添加到有序集合key中。如果某个元素member已经存在,则更新其score值,并将其重新插入合适的位置。

score可以是整数或双精度浮点数。

key不存在时,则创建一个新的有序集合并插入指定元素。key存在但不是有序集合时,返回一个错误。

复杂度、返回值:

  • 时间复杂度:O(M*log(N))N是有序集合的基数,M是要添加的新元素
  • 返回值:被成功添加的新元素的数量。

使用示例

# 添加单个元素
redis> ZADD page_rank 10 google.com
(integer) 1

# 添加多个元素
redis> ZADD page_rank 9 itbilu.com 8 bing.com
(integer) 2

redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "itbilu.com"
4) "9"
5) "google.com"
6) "10"

# 添加已存在元素,且 score 值不变
redis> ZADD page_rank 10 google.com
(integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES  # 没有改变
1) "bing.com"
2) "8"
3) "itbilu.com"
4) "9"
5) "google.com"
6) "10"

# 添加已存在元素,且改变 score 值
redis> ZADD page_rank 6 bing.com
(integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES  # bing.com 元素的 score 值被改变
1) "bing.com"
2) "6"
3) "itbilu.com"
4) "9"
5) "google.com"
6) "10"


2.1.2 ZINCRBY - 增加元素权重

ZINCRBY key increment member

为有序集合key的元素memberscore增加值incrementincrement可以是一个负数,用于减小元素的score值。

key不存在或元素不存在,执行 ZINCRBY key -5 member操作相当于ZADD key increment member

复杂度、返回值:

  • 时间复杂度:O(log(N))
  • 返回值:member新的score值;当key不是有序集合返回一个错误

使用示例

redis> ZSCORE salary tom
"2000"

redis> ZINCRBY salary 2000 tom
"4000"


查询有序集合时,可以查询其某一个或多个元素的。查询一个元素,可以通过ZRANK命令查询元素的排名,或使用ZSCORE命令查询元素的权重。而查询多个元素进,可以按正序/倒序、下标区间/权重区间查询元素。

2.2.1 ZCARD - 返回集合基数

ZCARD key

返回有序集合key的基数。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:有序集合key的基数;当集合不存在时,返回0

使用示例

# 添加一个元素
redis > ZADD salary 2000 tom
(integer) 1

redis > ZCARD salary
(integer) 1

 # 再添加一个元素
redis > ZADD salary 5000 jack  
(integer) 1

redis > ZCARD salary
(integer) 2

# 对不存在的有序集合进行 ZCARD 操作
redis > EXISTS non_exists_key   
(integer) 0

redis > ZCARD non_exists_key
(integer) 0


2.2.2 ZRANK - 返回指定元素的排名

ZRANK key member

返回有序集合key中的元素member的排名。元素成员按score值递增,相同score值的成员按字典排序。元素排名从0开始计数。

复杂度、返回值:

  • 时间复杂度:O(log(N))
  • 返回值:元素member的排名;如果key不是有序集合,返回nil

使用示例

# 显示所有成员及其 score 值
redis> ZRANGE salary 0 -1 WITHSCORES
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"

# tom 排名第二
redis> ZRANK salary tom
(integer) 1


2.2.3 ZSCORE - 返回指元素的权重

ZSCORE key member

返回有序集合key中,元素memberscore值。

复杂度、返回值:

  • 时间复杂度:O(1)
  • 返回值:指定元素的score值;如果元素不存在或key不存在,则返回nil

使用示例

redis> ZRANGE salary 0 -1 WITHSCORES
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

# 返回值是字符串形式
redis> ZSCORE salary peter
"3500"


2.2.4 ZCOUNT - 返回集合两个权重间的元素数

ZCOUNT key min max

返回有序集合keyscore值在minmax之间的元素数(包含值为minmax的元素)。

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,Mminmax之间的元素数
  • 返回值:有序集合key的基数;当集合不存在时,返回0

使用示例

# 测试数据
redis> ZRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "2000"
3) "peter"
4) "3500"
5) "tom"
6) "5000"

# 计算薪水在 2000-5000 之间的人数
redis> ZCOUNT salary 2000 5000
(integer) 3

# 计算薪水在 3000-5000 之间的人数
redis> ZCOUNT salary 3000 5000
(integer) 2


2.2.5 ZRANGE - 返回指定区间内的元素

ZRANGE key start stop [WITHSCORES]

返回有序集合key指定区间内的元素。元素成员按score值递增,相同score值的成员按字典排序。

startstop都是从0开始。当使用负数时,表示从集合的末尾开始计数。

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为结果集的基数。
  • 返回值:指定区间内的成员列表

使用示例

# 显示有序集合所有成员
redis > ZRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

# 返回有序集下标区间 1 至 2 的成员
redis > ZRANGE salary 1 2 WITHSCORES
1) "tom"
2) "5000"
3) "boss"
4) "10086"

# end 超出最大下标时
redis > ZRANGE salary 0 200000 WITHSCORES
1) "jack"
2) "3500"
3) "tom"
4) "5000"
5) "boss"
6) "10086"

# 当指定区间超出有序集合范围时
redis > ZRANGE salary 200000 3000000 WITHSCORES
(empty list or set)


2.2.6 ZREVRANGE - 倒序返回指定区间内的元素

ZREVRANGE key start stop [WITHSCORES]

返回有序集合key中,指定区间内的成员。score值按倒序(从大到小)顺序排序。

score按倒序排序外,此命令与ZRANGE命令完全一致。WITHSCORES用于指定是否同时返回元素的score

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为结果集的数量
  • 返回值:指定区间的元素

使用示例

# 递增排列
redis> ZRANGE salary 0 -1 WITHSCORES
1) "peter"
2) "3500"
3) "tom"
4) "4000"
5) "jack"
6) "5000"

# 递减排列
redis> ZREVRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "5000"
3) "tom"
4) "4000"
5) "peter"
6) "3500"


2.2.7 ZRANGEBYSCORE - 返回指定权重区间内的元素

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

返回有序集合key指定区间内的元素。元素成员按score值递增,相同score值的成员按字典排序。

可选参数LIMIT用于指定返回元素数量,offset用于指定便移量(类似SQL中的SELECT LIMIT offset, count )。WITHSCORES用于指定是否同时返回score

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为结果集的基数。
  • 返回值:指定区间内的成员列表

使用示例

# 测试数据
redis> ZADD salary 2500 jack
(integer) 0
redis> ZADD salary 5000 tom
(integer) 0
redis> ZADD salary 12000 peter
(integer) 0

# 显示整个有序集合
redis> ZRANGEBYSCORE salary -inf +inf
1) "jack"
2) "tom"
3) "peter"

# 显示整个有序集合及成员的 score 值
redis> ZRANGEBYSCORE salary -inf +inf WITHSCORES
1) "jack"
2) "2500"
3) "tom"
4) "5000"
5) "peter"
6) "12000"

# 工资 <=5000 的成员
redis> ZRANGEBYSCORE salary -inf 5000 WITHSCORES
1) "jack"
2) "2500"
3) "tom"
4) "5000"

# 工资大于 5000 小于等于 400000 的成员
redis> ZRANGEBYSCORE salary 5000 400000
1) "peter"


2.2.8 ZREVRANGEBYSCORE - 倒序返回指定权重区间内的元素

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

返回有序集合key中,score值位于maxmin(默认包含maxmin)区间内的成员。score值按递减(从大到小)顺序排序。

score按倒序排序外,此命令与ZRANGEBYSCORE命令完全一致。WITHSCORES用于指定是否同时返回元素的score

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为结果集的数量
  • 返回值:指定区间的元素

使用示例

redis > ZADD salary 10086 jack
(integer) 1
redis > ZADD salary 5000 tom
(integer) 1
redis > ZADD salary 7500 peter
(integer) 1
redis > ZADD salary 3500 joe
(integer) 1

# 倒序返回所有成员
redis > ZREVRANGEBYSCORE salary +inf -inf
1) "jack"
2) "peter"
3) "tom"
4) "joe"

# 倒序返回salary于 10000 和 2000 之间的成员
redis > ZREVRANGEBYSCORE salary 10000 2000
1) "peter"
2) "tom"
3) "joe"


2.3 有序集合移除元素

如果需要移除有序集合中的元素,可以使用ZREM移除指定的元素成员。也可以使用ZREMRANGEBYRANKZREMRANGEBYSCORE来移除指定下标区间或权重区间内的元素。

2.3.1 ZREM - 移除元素

ZREM key member [member ...]

移除有序集合key中的一个或多个元素member的排名,不存在成员将被忽略。

复杂度、返回值:

  • 时间复杂度:O(M*log(N))N是有序集合的基数,M为移除元素数量
  • 返回值:被成功移除的元素数量;如果key不是有序集合,会返回一个错误

使用示例

# 测试数据
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "itbilu.com"
4) "9"
5) "google.com"
6) "10"

# 移除单个元素
redis> ZREM page_rank google.com
(integer) 1

redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "itbilu.com"
4) "9"

# 移除多个元素
redis> ZREM page_rank itbilu.com bing.com
(integer) 2

redis> ZRANGE page_rank 0 -1 WITHSCORES
(empty list or set)

# 移除不存在元素
redis> ZREM page_rank non-exists-element
(integer) 0


2.3.2 ZREMRANGEBYRANK - 移除指定区间内的元素

ZREMRANGEBYRANK key start stop

移除有序集合key中,指定排名(rank)区间内的元素。

startstop用于指定元素区间,startstop包含在区间内。startstop的底数以0开始,也可以使用负数,如-1表示最后一个元素,依次类推。

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为移除元素数量
  • 返回值:被移除成员的数量

使用示例

# 测试数据
redis> ZADD salary 2000 jack
(integer) 1
redis> ZADD salary 5000 tom
(integer) 1
redis> ZADD salary 3500 peter
(integer) 1

# 移除 0 至 1 区间内的成员
redis> ZREMRANGEBYRANK salary 0 1
(integer) 2

# 有序集只剩下一个成员
redis> ZRANGE salary 0 -1 WITHSCORES
1) "tom"
2) "5000"


2.3.3 ZREMRANGEBYSCORE - 移除指定权重区间内的元素

ZREMRANGEBYSCORE key min max

移除有序集合key中,score值位于minmax(包含minmax)之间的元素。

复杂度、返回值:

  • 时间复杂度:O(log(N)+M)N是有序集合的基数,M为移除元素数量
  • 返回值:被移除成员的数量

使用示例

# 有序集合内的所有成员及其 score 值
redis> ZRANGE salary 0 -1 WITHSCORES
1) "tom"
2) "2000"
3) "peter"
4) "3500"
5) "jack"
6) "5000"

# 移除所有salary 在 1500 到 3500 内的员工
redis> ZREMRANGEBYSCORE salary 1500 3500
(integer) 2

# 剩余的成员
redis> ZRANGE salary 0 -1 WITHSCORES
1) "jack"
2) "5000"


2.4 交、并集计算

有序集合支持简单的聚合操作,可以使用ZUNIONSTORE命令计算多个有序集合的并集,或使用ZINTERSTORE命令计算多个有序集合的交集。

2.4.1 ZUNIONSTORE - 并集操作

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

计算一或多个有序集合的并集,并将结果存储到destinationscore中。

参数

  • WEIGHTS - 乘法因子,所有有序集合值在传递聚合函数前,都要乘以该因子。默认值为1
  • AGGREGATE - 指定结果集的聚合方式。默认使用SUM(求合)。可选值还有MIN(计算最小值)、MAX(计算最大值)

复杂度、返回值:

  • 时间复杂度:O(N)+O(M log(M))N为有序集合的总数,M结果集的基数
  • 返回值:保存到结果集destination的基数

使用示例

redis> ZRANGE programmer 0 -1 WITHSCORES
1) "peter"
2) "2000"
3) "jack"
4) "3500"
5) "tom"
6) "5000"

redis> ZRANGE manager 0 -1 WITHSCORES
1) "herry"
2) "2000"
3) "mary"
4) "3500"
5) "bob"
6) "4000"

# 除 programmer 外,其它成员增加 salary
redis> ZUNIONSTORE salary 2 programmer manager WEIGHTS 1 3
(integer) 6

redis> ZRANGE salary 0 -1 WITHSCORES
1) "peter"
2) "2000"
3) "jack"
4) "3500"
5) "tom"
6) "5000"
7) "herry"
8) "6000"
9) "mary"
10) "10500"
11) "bob"
12) "12000"


2.4.2 ZINTERSTORE - 交集操作

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]

计算一或多个有序集合的交集,并将结果存储到destinationscore中。

可选参数WEIGHTSAGGREGATEZUNIONSTORE相同。

复杂度、返回值:

  • 时间复杂度:(N*K)+O(M*log(M))N为指定有序集合中基数最小的有序集,M为指定有序集合的数量,M结果集的基数
  • 返回值:保存到结果集destination的基数

使用示例

redis > ZADD mid_test 70 "Li Lei"
(integer) 1
redis > ZADD mid_test 70 "Han Meimei"
(integer) 1
redis > ZADD mid_test 99.5 "Tom"
(integer) 1

redis > ZADD fin_test 88 "Li Lei"
(integer) 1
redis > ZADD fin_test 75 "Han Meimei"
(integer) 1
redis > ZADD fin_test 99.5 "Tom"
(integer) 1

# 保存交集
redis > ZINTERSTORE sum_point 2 mid_test fin_test
(integer) 3

redis > ZRANGE sum_point 0 -1 WITHSCORES
1) "Han Meimei"
2) "145"
3) "Li Lei"
4) "158"
5) "Tom"
6) "199"