有序集合每个字符串元素都关联到一个双精度64位的浮点型数字字符串score,里面的元素总是通过score进行着排序,因此它是可以检索的一系列元素
默认升序排列,即通过命令ZRANGE实现;如果要按照降序排列,需要通过命令ZREVRANGE实现
当score即得分一样时,按照字典顺序对member进行排序,字典排序用的是二进制,它比较的是字符串的字节数组,所以实际上是比较ASCII码
底层结构
Ziplist
有序集合对象的编码可以是ziplist或者skiplist,同时满足以下条件时使用ziplist编码:
- 元素数量小于128个
- 所有member的长度都小于64字节
以上两个条件的上限值可通过zset-max-ziplist-entries和zset-max-ziplist-value来修改
ziplist编码的有序集合使用紧挨在一起的压缩列表节点来保存,第一个节点保存member,第二个保存score
ziplist内的集合元素按score从小到大排序,score较小的排在表头位置
Skiplist
skiplist编码的有序集合底层是一个命名为zset的结构体,而一个zset结构同时包含一个字典和一个跳跃表
跳跃表按score从小到大保存所有集合元素,而字典则保存着从member到score的映射,这样就可以用O(1)的复杂度来查找member对应的score值,虽然同时使用两种结构,但它们会通过指针来共享相同元素的member和score,因此不会浪费额外的内存
向有序集合中添加score和element 时间复杂度 O(logN)
获取element的分数 时间复杂度O(1)
自增element的分数 时间复杂度O(1)
返回有序集合中元素的个数 时间复杂度O(1)
多维度排序
以手机应用商店的热门榜单排序为例:首先按照APP的下载量倒序排序,如果下载量一样,则按照最后更新时间倒序排列
SortedSet排序因子score,它是一个双精度64位的浮点型数字字符串
我们如何实现多维度排序?
构造一个特殊的score,以这个案例为例,排序影响因子是下载量和更新时间,那么我们可以构造一个这样特殊的浮点类型的score:整数部分就是下载量,小数部分就是最后更新时间戳
假设有5个app的下载量和最后更新时间分别如下(说明:更新时间只精确到秒):
wechat-下载量:12000000,最后更新时间:1564022201;其score为:12000000.1564022201
qq-下载量:12000000,最后更新时间:1564022222;其score为:12000000.1564022222
tiktok-下载量:9808900,最后更新时间:1563552267;其score为:9808900.1563552267
taobao-下载量:11006600,最后更新时间:1564345601;其score为:11006600.1564345601
alipay-下载量:11006600,最后更新时间:1564345600;其score为:11006600.1564345600
接下来,我们通过如下命令将这5个APP用SortedSet数据类型保存到Redis中:
zadd TopApp 12000000.1564022201 wechat 12000000.1564022222 qq 9808900.1563552267 tiktok 11006600.1564345601 taobao 11006600.1564345600 alipay
保存后,我们看一下排序结果是否符合我们的预期:
127.0.0.1:6379> zrevrange TopApp 0 -1
1) "qq"
2) "wechat"
3) "taobao"
4) "alipay"
5) "tiktok"