有序集合对象
有序集合对象的成员按照分数递增的顺序排序,分数相同的成员按照字典顺序排序,并且每个成员都是唯一的。每个有序集合对象最多可以存储 232-1 个元素。
编码方式
有序集合对象的编码方式:ziplist、skiplist。
当有序集合对象同时满足如下两个条件时,则使用 ziplist 编码;否则使用 skiplist 编码。
- 有序集合对象的所有成员的长度 <= 64 字节。(zset-max-ziplist-value)
- 有序集合对象的元素个数 <= 128 个。(zset-max-ziplist-entries)
ziplist编码
ziplist 编码的有序集合对象使用压缩列表作为底层实现。每个有序集合对象的元素使用两个紧挨在一起的压缩列表节点保存。第一个压缩列表节点保存有序集合对象的元素的成员,第二个节点保存有序集合对象的元素的分值。
压缩列表的元素按照分值由小到大的顺序排序,分值较小的元素放到表头的方向,分值较大的元素放到表尾的方向。
skiplist编码
skiplist 编码的有序集合对象使用 zset 结构作为底层实现。一个 zset 结构同时包含一个字典和一个跳跃表。
typedef struct zset {
zskiplist *zsl;
dict *dict;
} zset;
zset 结构中的 zsl 跳跃表按照分值由小到大的顺序保存了所有元素。每一个跳跃表节点保存了一个元素。跳跃表节点的 object 属性保存了元素的成员,score 属性保存了元素的分值。通过跳跃表,可以对有序集合对象进行范围操作,比如 zrank、zrange 等。
zset 结构中的 dict 字典提供了从成员到分值的映射。字典中的每个键值对保存了一个元素。字典的键保存了元素的成员,字典的值保存了元素的分值。可以使用 0(1) 的时间复杂度查找成员对应的分值,比如 zscore 命令。
跳跃表和字典这两种数据结构会通过指针共享同一个元素的成员和分值。
常见的使用场景
与排行榜相关的场景。
-
每次点击新闻:zincrby hotNews:20190819 1 XXX
-
展示当日排行前十:zrevrange hotNews:20190819 0 10 withscores
-
七日搜索榜单计算:zunionstore hotNews:20190813-20190819 hotNews:20190813 … hotNews:20190819
命令
zadd 命令 - 添加一个或者多个元素到有序集合对象中
时间复杂度:每个元素都是 0(logn)
语法格式:zadd <key> [nx | xx] [gt | lt] [ch] [incr] <score> <member> [<score> <member> ...]
返回值:一般会返回新添加的元素的个数。如果使用了 ch 参数,则返回新添加的元素的个数加已有元素的分值发生变化的个数之和。如果使用了 incr 参数,则返回元素更新后的分值。
nx:只能添加新的元素。gt、lt 参数与 nx 参数互斥。
xx:只能修改已有的元素。
gt:(6.2.0 版本)只有当元素的新的分值比原来的大