有序集SortedSet算是redis中一个很有特色的数据结构,通过这篇文章来总结一下这块知识点。
原文地址:www.jianshu.com/p/75ca5a359…
一、有序集SortedSet命令简介
redis中的有序集,允许用户使用指定值对放进去的元素进行排序,并且基于该已排序的集合提供了一系列丰富的操作集合的API。
举例如下:
1 | 复制代码//添加元素,table1为有序集的名字,100为用于排序字段(redis把它叫做score),a为我们要存储的元素 |
在有序集中,用于排序的值叫做score,实际存储的值叫做member。
由于有序集中提供的API较多,这里只举了几个常见的,具体可以参考redis文档。
关于有序集,我们有一个十分常见的使用场景就是用户评论。在APP或者网站上发布一条消息,下面会有很多评论,通常展示是按照发布时间倒序排列,这个需求就可以使用有序集,以发布评论的时间戳作为score,然后按照展示评论的数量倒序查找有序集。
二、有序集SortedSet命令源码分析
老规矩,我们还是从server.c文件中的命令表中找到相关命令的处理函数,然后一一分析。
依旧从添加元素开始,zaddCommand函数:
1 | 复制代码void zaddCommand(client *c) { |
这里可以看到流程转向了zaddGenericCommand,并且传入了一个模式标记。
关于SortedSet的操作模式这里简单说明一下,先来看一条完整的zadd命令:
1 | 复制代码zadd key [NX|XX] [CH] [INCR] score member [score member ...] |
其中的可选项我们依次看下:
- NX表示如果元素存在,则不执行替换操作直接返回。
- XX表示只操作已存在的元素。
- CH表示返回修改(包括添加,更新)元素的数量,只能被ZADD命令使用。
- INCR表示在原来的score基础上加上新的score,而不是替换。
上面代码片段中的ZADD_NONE表示普通操作。
接下来看下zaddGenericCommand函数的源码,很长,耐心一点点看:
1 | 复制代码void zaddGenericCommand(client *c, int flags) { |
代码有点长,来张图看一下存储结构:
有序集存储结构
注:每个entry都是由score+member组成
有了上面的结构图以后,可以想到删除操作应该就是根据不同的存储结构进行,如果是ziplist就执行链表删除,如果是哈希表+跳表结构,那就要把两个集合都进行删除。真实逻辑是什么呢?
我们来看下删除函数zremCommand的源码,相对短一点:
1 | 复制代码void zremCommand(client *c) { |
看下具体的删除操作源码:
1 | 复制代码//参数zobj为有序集,ele为要删除的元素 |
最后看一个查询函数zrangeCommand源码,也是很长,汗~,不过放心,有了上面的基础,大致也能猜到查询逻辑应该是什么样子的:
1 | 复制代码void zrangeCommand(client *c) { |
上面就是关于有序集SortedSet的添加,删除,查找的源码。可以看出SortedSet会根据存放元素的数量选择ziplist或者哈希表+跳表两种数据结构进行实现,之所以源码看上去很长,主要原因也就是要根据不同的数据结构进行不同的代码实现。只要掌握了这个核心思路,再看源码就不会太难。
三、有序集SortedSet命令总结
有序集的逻辑不难,就是代码有点长,涉及到ziplist,skiplist,dict三套数据结构,其中除了常规的dict之外,另外两个数据结构内容都不少,准备专门写文章进行总结,就不在这里赘述了。本文主要目的是总结一下有序集SortedSet的实现原理。
本文转载自: 掘金