一. 有序集合概述
Redis 有序集合对象和集合对象一样也是 string 类型元素的集合, 且不允许重复的成员. 不同的是每个元素都会关联一个 double 类型的分数. Redis 正是通过分数来为集合中的成员进行从小到大的排序. 有序集合的成员是唯一的, 但分数 (score) 却可以重复.
在前面第 9 章中讲到 Redis 数据对象对应不同底层的数据结构, 对于有序集合对象 编码可以是 ziplist 或者 skiplist 二种. skiplist 编码的底层数据结构可以参考 "redis 系列 7 数据结构之跳跃表".ziplist 编码的压缩列表结构以后再讲.
1.1 ziplist 编码
ziplist 编码的有序集合对象使用压缩列表作为底层实现, 每个集合元素使用两个紧挨在一起的压缩列表节点来保存, 第一个节点保存元素的成员(member), 而第二个元素则保存元素的分值(score). 压缩列表的集合元素按分值从小到大进行排序, 分值较小的元素被放置在靠近表头的方向, 分值较大的元素则被放置在靠近表尾的方向.
下例中, 使用 zadd 命令, 创建一个有序集合对象作为 price 键的值. 并且该对象使用的编码是 ziplist.
- 127.0.0.1:6379> zadd price 8.5 apple 5.0 banana
- (integer) 2
- 127.0.0.1:6379> object encoding price
- "ziplist"
1.2 skiplist 编码
skiplist 编码的有序集合对象使用字典和跳跃表作为底层实现, 如果一个有序集合包含的元素数量比较多, 又或者有序集合中元素的成员是比较长的字符串时, Redis 就会使用跳跃表来作为有序集合键的底层实现.
下例中, 还是使用 zadd 命令, 创建一个有序集合对象作为 store 键的值. 并且该对象使用的编码是 skiplist.
127.0.0.1:6379> zadd store 1.0
"long_long_long_long_long_long_long_long_long_long_long_long..." -- 省去了字符, 大于 64 字节
- 127.0.0.1:6379> object encoding store
- "skiplist"
1.3 编码的转换
当有序集合可以同时满足以下两个条件时, 对象使用 ziplist 编码:
(1) 有序集合保存的元素数量小于 128 个.
(2) 有序集合的所有元素成员的长度都小于 64 字节.
- 127.0.0.1:6379> config get zset-max-ziplist-value
- 1) "zset-max-ziplist-value"
- 2) "64"
- 127.0.0.1:6379> config get zset-max-ziplist-entries
- 1) "zset-max-ziplist-entries"
- 2) "128"
二. 有序集合对象命令实现
-- Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中. 返回被成功添加的新成员的数量, 不包括那些被更新的, 已经存在的成员.
- 127.0.0.1:6379> zadd price 8.5 apple 5.0 banana
- (integer) 2
-- Zcard 命令用于计算集合中元素的数量.
- 127.0.0.1:6379> zcard price
- (integer) 2
-- Zcount 命令用于计算有序集合中指定分数区间的成员数量
- 127.0.0.1:6379> zrange price 0 -1 withscores
- 1) "banana"
- 2) "5"
- 3) "pear"
- 4) "6"
- 5) "apple"
- 6) "8.5"
127.0.0.1:6379> zcount price 5.0 7.0 -- 取 scores 值范围
(integer) 2
-- Zincrby 命令对有序集合中指定成员的分数加上增量 increment, 可以通过传递一个负数值 increment , 让分数减去相应的值.
- 127.0.0.1:6379> zrange price 0 -1 withscores
- 1) "pear"
- 2) "6"
127.0.0.1:6379> zincrby price 2.5 Pear -- 添加 2.5 元
"8.5"
-- Zinterstore 命令计算给定的一个或多个有序集的交集, 其中给定 key 的数量必须以 numkeys 参数指定, 并将该交集 (结果集) 储存到 destination . 结果集中分数值是成员分数值之和.
127.0.0.1:6379> ZADD mid_test 70 "Li Lei" -- 第一个 key mid_test
- (integer) 1
- 127.0.0.1:6379> ZADD mid_test 70 "Han Meimei"
- (integer) 1
127.0.0.1:6379> ZADD fin_test 88 "Li Lei" -- 第二个 key fin_test
- (integer) 1
- 127.0.0.1:6379> ZADD fin_test 75 "Han Meimei"
- (integer) 1
127.0.0.1:6379> zinterstore sum_point 2 mid_test fin_test -- sum_point 是 destination,2 是二个 key
(integer) 2
127.0.0.1:6379> zrange sum_point 0 -1 withscores -- 分数值之和
- ) "Han Meimei"
- ) "145"
- ) "Li Lei"
- ) "158"
--Zlexcount 命令在计算有序集合中指定字典区间内成员数量.
- 127.0.0.1:6379> zadd myzset 1 a 2 b 3 c 4 d 5 e 6 f 7 g
- (integer) 7
127.0.0.1:6379> zlexcount myzset [c [g -- 获取 c 到 g 的区间数量
(integer) 5
-- Zrange 返回有序集中, 指定区间内的成员, 其中成员的位置按分数值递增 (从小到大) 来排序.
- 127.0.0.1:6379> zrange price 0 -1 withscores
- 1) "banana"
- 2) "5"
- 3) "pear"
- 4) "6"
- 5) "apple"
- 6) "8.5"
-- Zrangebylex 通过字典区间返回有序集合的成员.
- 127.0.0.1:6379> zadd myzset 1 a 2 b 3 c 4 d 5 e 6 f 7 g
- (integer) 7
- 127.0.0.1:6379> zrangebylex myzset [c [g
- 1) "c"
- 2) "d"
- 3) "e"
- 4) "f"
- 5) "g"
-- Zrangebyscore 返回有序集合中指定分数区间的成员列表. 有序集成员按分数值递增 (从小到大) 次序排列. 更多用法见官方文档
- 127.0.0.1:6379> ZADD salary 2500 jack
- (integer) 1
- 127.0.0.1:6379> ZADD salary 5000 tom
- (integer) 1
- 127.0.0.1:6379> ZADD salary 12000 peter
- (integer) 1
127.0.0.1:6379> zrangebyscore salary 2000 6000 withscores -- 返回工资范围
- ) "jack"
- ) "2500"
- ) "tom"
- ) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 5000 WITHSCORES -- 返回工资小于 5000 范围
- ) "jack"
- ) "2500"
- ) "tom"
- ) "5000"
--Zrank 返回有序集中指定成员的排名. 其中有序集成员按分数值递增 (从小到大) 顺序排列. 下面是 jack 分值排名 0 位, peter 分值排名 2 位.
- 127.0.0.1:6379> zrank salary jack
- (integer) 0 -- 2500
- 127.0.0.1:6379> zrank salary peter
- (integer) 2 -- 12000
-- Zrem 命令用于移除有序集中的一个或多个成员, 不存在的成员将被忽略.
- 127.0.0.1:6379> ZRANGE salary 0 -1 WITHSCORES
- 1) "jack"
- 2) "2500"
- 3) "tom"
- 4) "5000"
- 5) "peter"
- 6) "12000"
127.0.0.1:6379> zrem salary jack -- 移除 jack 成员成功
(integer) 1
--Zremrangebylex 命令用于移除有序集合中给定的字典区间的所有成员.
- 127.0.0.1:6379> zrange myzset 0 -1
- 1) "a"
- 2) "b"
- 3) "c"
- 4) "d"
- 5) "e"
- 6) "f"
- 7) "g"
127.0.0.1:6379> zremrangebylex myzset [a [c -- 移除了 a 到 c 的成员数据
(integer) 3
--Zremrangebyrank 命令用于移除有序集中, 指定排名 (rank) 区间内的所有成员.
- 127.0.0.1:6379> zrange salary 0 -1
- 1) "tom"
- 2) "peter"
127.0.0.1:6379> zremrangebyrank salary 0 0 -- 移除了分值排名为 0 的成员
(integer) 1 -- 称除了 tom 成员分值排 0, peter 分值排 1
- 127.0.0.1:6379> zrange salary 0 -1
- 1) "peter"
-- Zremrangebyscore 命令用于移除有序集中, 指定分数 (score) 区间内的所有成员.
- 127.0.0.1:6379> zrange salary 0 -1
- 1) "peter"
127.0.0.1:6379> zremrangebyscore salary 10000 13000 -- 移除分值的范围, peter 分值为 12000
(integer) 1
--Zrevrange 命令返回有序集中, 指定区间内的成员, 分数值 (从大到小)来排列. 与 zrange 命令一样, 分值排列相反.
- 127.0.0.1:6379> zrevrange salary 0 -1 withscores
- 1) "peter"
- 2) "12000"
- 3) "tom"
- 4) "5000"
- 5) "jack"
- 6) "2500"
-- Zrevrangebyscore 返回有序集中指定分数区间内的所有的成员. 有序集成员按分数值 (从大到小)的次序排列.
127.0.0.1:6379> zrevrangebyscore salary 6000 2000 withscores -- 返回分值范围
- ) "tom"
- ) "5000"
- ) "jack"
- ) "2500"
-- Zrevrank 命令返回有序集中成员的排名. 其中有序集成员按分数值 (从大到小) 排序
127.0.0.1:6379> zrevrank salary tom
(integer) 1 --tom 工资排名第二
127.0.0.1:6379> zrevrank salary peter
(integer) 0 --peter 工资排名第一
-- Zscore 命令返回有序集中, 成员的分数值.
- 127.0.0.1:6379> zscore salary peter
- "12000"
--Zunionstore 命令计算给定的一个或多个有序集的并集, 其中给定 key 的数量必须以 numkeys 参数指定, 并将该并集 (结果集) 储存到 destination .
127.0.0.1:6379> zrange salary 0 -1 withscores -- 第一个 key
- ) "jack"
- ) "2500"
- ) "tom"
- ) "5000"
- ) "peter"
- ) "12000"
127.0.0.1:6379> zrange salary2 0 -1 withscores -- 第二个 key
- ) "tom"
- ) "500"
- ) "jack"
- ) "1000"
127.0.0.1:6379> zunionstore salaries 2 salary salary2 -- 合并到 salaries 的 key 中
- (integer) 3
- 127.0.0.1:6379> zrange salaries 0 -1 withscores
- 1) "jack"
- 2) "3500"
- 3) "tom"
- 4) "5500"
- 5) "peter"
- 6) "12000"
来源: https://www.cnblogs.com/MrHSR/p/9983339.html