Redis 有序集合(Sorted Set)和集合(Set)一样也是 String 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数,redis 正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
有序集合的底层数据结构
有序集合的编码可以是压缩列表(ziplist)或者跳跃表(skiplist)。
压缩列表
ziplist 编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),而第二个元素则保存元素的分值(score)。
压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向,而分值较大的元素则被放置在靠近表尾的方向。
需要注意的是,当有序集合对象可以同时满足以下两个条件时,对象才使用 ziplist 编码:
- 当有序集合保存的元素数量小于 zset-max-ziplist-entries 配置的值,默认是 128;
- 当有序集合保存的所有元素成员(member)的长度都小于 zset-max-ziplist-value 配置的值,默认是 64 字节。
如果不能满足以上 2 个条件的有序集合对象将使用跳跃表(skiplist)编码。
跳跃表
skiplist 编码的有序集合对象使用 zset 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表:
typedef struct zset {
// 跳跃表
zskiplist *zsl;
// 字典
dict *dict;
} zset;
zset 结构中的 zsl 跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:跳跃表节点的 object 属性保存了元素的成员,而跳跃表节点的 score 属性则保存了元素的分值。通过这个跳跃表,程序可以对有序集合进行范围型操作,比如 ZRANGE、ZRANK 等命令就是基于跳跃表 API 来实现的。
此外,zset 结构中的 dict 字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素:字典的键保存了元素的成员,而字典的值则保存了元素的分值。通过这个字典,程序可以用 O(1) 复杂度查找指定成员的分值,ZSCORE 命令就是根据这一特性实现的,而很多其他有序集合命令都在实现的内部用到了这一特性。
值得一提的是,虽然 zset 结构同时使用跳跃表和字典来保存有序集合元素,但这两种数据结构都会通过指针来共享相同元素的成员和分值,所以同时使用跳跃表和字典来保存集合元素不会产生任何重复成员或者分值,也不会因此而浪费额外的内存。
跳跃表的具体存储形式,如下图:
Redis 有序集合命令
可用版本 | 命令及描述 |
---|---|
>=5.0.0 |
BZPOPMAX key [key ...] timeout 返回非空有序集合 key 中分数最大的成员。 |
>=5.0.0 |
BZPOPMIN key [key ...] timeout 返回非空有序集合 key 中分数最小的成员。 |
>=1.2.0 |
ZADD key [NX|XX] [CH] [INCR] score member [score member ...] 将一个或多个 member 元素及其 score 值加入到有序集合指定 key 当中。 |
>=1.2.0 |
返回有序集合指定 key 的基数(即成员的个数)。 |
>=2.0.0 |
返回有序集合指定 key 中,score 值在 min 和 max 之间的成员的数量。 |
>=1.2.0 |
为有序集合指定 key 的成员 member 的 score 值加上增量 increment。 |
>=2.0.0 |
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] 计算给定的一个或多个有序集的交集,并将该交集(结果集)储存到 destination。 |
>=2.8.9 |
计算有序集合中指定字典区间内成员数量。 |
>=5.0.0 |
删除并返回有序集合 key 中的最多 count 个具有最高得分的成员。 |
>=5.0.0 |
删除并返回有序集合 key 中的最多 count 个具有最低得分的成员。 |
>=1.2.0 |
ZRANGE key start stop [WITHSCORES] 返回有序集合 key 中,指定区间内的成员。 |
>=2.8.9 |
ZRANGEBYLEX key min max [LIMIT offset count] 返回指定成员区间内的成员,按成员字典正序排序,且成员的分数必须相同。 |
>=1.0.5 |
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 返回有序集合 key 中,所有 score 值介于 min 和 max 之间的成员。 |
>=2.0.0 |
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。 |
>=1.2.0 |
返回移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。 |
>=2.8.9 |
删除名称按字典由低到高排序的成员之间所有成员。 |
>=2.0.0 |
ZREMRANGEBYRANK key start stop 移除有序集 key 中,指定排名(rank)区间内的所有成员。 |
>=1.2.0 |
移除有序集 key 中,所有 score 值介于 min 和 max 之间的成员。有序集合成员按 score 值递增(从小到大)次序排列。 |
>=1.2.0 |
ZREVRANGE key start stop [WITHSCORES] 返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递减(从大到小)来排列。 |
>=2.8.9 |
ZREVRANGEBYLEX key max min [LIMIT offset count] 返回指定成员区间内的成员,成员按字典倒序排序。 |
>=2.2.0 |
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] 返回有序集合 key 中,所有 score 值介于 max 和 min 之间的成员。有序集合成员按 score 值递减(从大到小)次序排列。 |
>=2.0.0 |
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)顺序排列。 |
>=2.8.0 |
ZSCAN key cursor [MATCH pattern] [COUNT count] 用于迭代有序集合中的元素(包括元素成员和元素分值)。 |
>=1.2.0 |
返回有序集 key 中,成员 member 的 score 值。 |
>=2.0.0 |
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] 计算给定的 numkeys 个有序集合的并集,并且把结果放到 destination 中。 |