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
的元素member
的score
增加值increment
。increment
可以是一个负数,用于减小元素的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"
2.2 有序集合查询
查询有序集合时,可以查询其某一个或多个元素的。查询一个元素,可以通过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
中,元素member
的score
值。
复杂度、返回值:
- 时间复杂度:
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
返回有序集合key
,score
值在min
和max
之间的元素数(包含值为min
和max
的元素)。
复杂度、返回值:
- 时间复杂度:
O(log(N)+M)
,N
是有序集合的基数,M
为min
和max
之间的元素数 - 返回值:有序集合
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
值的成员按字典排序。
start
和stop
都是从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
值位于max
和min
(默认包含max
和min
)区间内的成员。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
移除指定的元素成员。也可以使用ZREMRANGEBYRANK
或ZREMRANGEBYSCORE
来移除指定下标区间或权重区间内的元素。
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)区间内的元素。
start
和stop
用于指定元素区间,start
和stop
包含在区间内。start
和stop
的底数以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
值位于min
和max
(包含min
和max
)之间的元素。
复杂度、返回值:
- 时间复杂度:
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]
计算一或多个有序集合的并集,并将结果存储到destination
的score
中。
参数
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]
计算一或多个有序集合的交集,并将结果存储到destination
的score
中。
可选参数WEIGHTS
、AGGREGATE
与ZUNIONSTORE
相同。
复杂度、返回值:
- 时间复杂度:
(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"