更多精彩文章,关注公众号【ToBeTopJavaer】,更有数万元精品vip资源免费等你来拿!!!
本文咱们要剖析的基本类型是ZSet,下面咱们将深刻源码剖析Redis中ZSet的实现。php
一、sorted set,有序的 set,每一个元素有个 score。java
二、score 相同时,按照 key 的 ASCII 码排序。python
数据结构对比
添加元素redis
zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python
获取所有元素算法
zrange myzset 0 -1 withscoreszrevrange myzset 0 -1 withscores
根据分值区间获取元素数组
zrangebyscore myzset 20 30
移除元素,也能够根据 score rank 删除ruby
zrem myzset php cpp
统计元素个数数据结构
zcard myzset
分值递增dom
zincrby myzset 5 python
根据分值统计个数函数
zcount myzset 20 60
获取元素 rank
zrank myzset java
获取元素 score
zsocre myzset java
也有倒序的 rev 操做(reverse)
同时知足如下条件时使用 ziplist 编码:
一、元素数量小于 128 个
二、全部 member 的长度都小于 64 字节
在 ziplist 的内部,按照 score 排序递增来存储。插入的时候要移动以后的数据。
对应 redis.conf 参数:
超过阈值以后,使用 skiplist+dict 存储。
咱们先来看一下有序链表:
在这样一个链表中,若是咱们要查找某个数据,那么须要从头开始逐个进行比较,直到找到包含数据的那个节点,或者找到第一个比给定数据大的节点为止(没找到)。
也就是说,时间复杂度为 O(n)。一样,当咱们要插入新数据的时候,也要经历一样的查找过程,从而肯定插入位置。
而二分查找法只适用于有序数组,不适用于链表。
假如咱们每相邻两个节点增长一个指针(或者理解为有三个元素进入了第二层),让指针指向下下个节点。
这样全部新增长的指针连成了一个新的链表,但它包含的节点个数只有原来的一半(上图中是 7, 19, 26)。在插入一个数据的时候,决定要放到那一层,取决于一个算法(在 redis 中 t_zset.c 有一个 zslRandomLevel 这个方法)。
如今当咱们想查找数据的时候,能够先沿着这个新链表进行查找。当碰到比待查数据大的节点时,再回到原来的链表中的下一层进行查找。好比,咱们想查找 23,查找的路径是沿着下图中标红的指针所指向的方向进行的:
1. 23 首先和 7 比较,再和 19 比较,比它们都大,继续向后比较。
2. 但 23 和 26 比较的时候,比 26 要小,所以回到下面的链表(原链表),与 22比较。
3. 23 比 22 要大,沿下面的指针继续向后和 26 比较。23 比 26 小,说明待查数据 23 在原链表中不存在。
在这个查找过程当中,因为新增长的指针,咱们再也不须要与链表中每一个节点逐个进行比较了。须要比较的节点数大概只有原来的一半。这就是跳跃表。
typedef struct zskiplistNode { sds ele; /* zset 的元素 */ double score; /* 分值 */ struct zskiplistNode *backward; /* 后退指针 */ struct zskiplistLevel { struct zskiplistNode *forward; /* 前进指针, 对应 level 的下一个节点 */ unsigned long span; /* 从当前节点到下一个节点的跨度(跨越的节点数) */ } level[]; /* 层 */ } zskiplistNode; typedef struct zskiplist { struct zskiplistNode *header, *tail; /* 指向跳跃表的头结点和尾节点 */ unsigned long length; /* 跳跃表的节点数 */ int level; /* 最大的层数 */ } zskiplist; typedef struct zset { dict *dict; zskiplist *zsl; } zset; 复制代码
随机获取层数的函数(源码):
int zslRandomLevel(void) { int level = 1; while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) level += 1; return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL; }复制代码
id 为 6001 的新闻点击数加 **1:zincrby hotNews:20190926 1 n6001
获取今天点击最多的 15 条:zrevrange hotNews:20190926 0 15 withscores**
更多精彩文章,关注公众号【ToBeTopJavaer】,更有数万元精品vip资源免费等你来拿!!!
``