这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
16redis基本类型之有序集合对象
有序集合的编码可以是ziplist或者skiplist
有序集合保存的元素数量小于128个,所有元素成员的长度都小于64字节的时候,使用ziplist编码,否则使用skiplist编码
ziplist编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向,分值较大的元素被放置在靠近表尾的方向。
skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表
/* ZSETs use a specialized version of Skiplists */
/*
* 跳跃表节点
*/
typedef struct zskiplistNode {
// member 对象
robj *obj;
// 分值
double score;
// 后退指针
struct zskiplistNode *backward;
// 层
struct zskiplistLevel {
// 前进指针
struct zskiplistNode *forward;
// 这个层跨越的节点数量
unsigned int span;
} level[];
} zskiplistNode;
/*
* 跳跃表
*/
typedef struct zskiplist {
// 头节点,尾节点
struct zskiplistNode *header, *tail;
// 节点数量
unsigned long length;
// 目前表内节点的最大层数
int level;
} zskiplist;
/*
* 有序集
*/
typedef struct zset {
// 字典
dict *dict;
// 跳跃表
zskiplist *zsl;
} zset;
zset结构中的zsl跳跃表按分值从小到大保存所有集合元素,每个跳跃表节点都保存了一个集合元素:跳跃表节点的object属性保存了元素的成员,score属性保存元素的分值。zrank zrange命令就是基于跳跃表API来实现的。
zset结构中的dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素:字典的键保存了元素的成员,而字典的值保存了元素的分值。查找给定成员复杂度为O(1),zscore命令就是根据这个实现的
有序集合每个元素的成员都是一个字符串对象,而每个元素的分值都是一个double类型的浮点数。
虽然zset结构使用跳跃表和字典来保存有序集合元素,但这两个数据结构通过指针来共享相同元素的成员和分值,因此不会浪费内存。
为什么有序集合需要同时使用跳跃表和字典实现?
提高性能。单独使用字典来实现有序集合虽然查找成员的分值的复杂度为O(1),但是字典以无序方式保存,执行范围型的命令,程序都需要对字典保存的所有元素进行排序,时间复杂度变高。单独使用跳跃表实现有序集合,范围型操作的时间复杂度变低,但没有字典,根据成员查找分值的复杂度变高。
常用命令
ZADD key score member
# 添加单个元素
redis> ZADD page_rank 10 google.com
(integer) 1
# 添加多个元素
redis> ZADD page_rank 9 baidu.com 8 bing.com
(integer) 2
redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.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) "baidu.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) "baidu.com"
4) "9"
5) "google.com"
6) "10"
ZSCORE key member
回有序集 key 中,成员 member 的 score 值。