redis-zset数据结构探索
Posted ginkgo-leaf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis-zset数据结构探索相关的知识,希望对你有一定的参考价值。
redis用的人比较多,其中zset大家都熟悉,主要用于排名场景。
zset数据结构,分成两部分,一部分是用于排序,一部分用于缓存键值。
先看看结构:
typedef struct zset { dict *dict; //缓存 zskiplist *zsl; //排序结构 } zset;
上面,跳跃表用于排序结构,可以按照名次,积分查找对应键, 时间复杂度: log(n)。
按照名次,积分范围查找一系列键时, 先查询满足条件的第一个键,然后当前键查找后续键, 时间复杂度: log(n) + o(m), n=总键数, m=查询结果键数。
跳跃表结构:
typedef struct zskiplist { struct zskiplistNode *header, *tail; //结点头:用于顺序查询,常用方式; 结点尾:用于倒序简单查询。 unsigned long length; //结点数 int level; //跳跃层级 } zskiplist;
结点结构:
typedef struct zskiplistNode { robj *obj; //键 double score; //积分 struct zskiplistNode *backward; //前一个结点, 和level[0]可看作双链表 struct zskiplistLevel { //跳跃层关系, 每层都是单链表 struct zskiplistNode *forward; //此层下一个结点 unsigned int span; //此层下一个结点和当前结点距离(两者隔了多少结点) } level[]; //最多32层 } zskiplistNode;
查询:
根据名次范围查询
void zrangeGenericCommand(client *c, int reverse) { ...... zset *zs = zobj->ptr; //zset结构变量 zskiplist *zsl = zs->zsl; //跳跃表 zskiplistNode *ln; robj *ele; /* Check if starting point is trivial, before doing log(N) lookup. */ if (reverse) { //是否倒序查询 ln = zsl->tail; //默认取尾结点 if (start > 0) ln = zslGetElementByRank(zsl,llen-start); //如果start>0, 则取对应结点 } else { ln = zsl->header->level[0].forward; //默认取第一个结点 if (start > 0) ln = zslGetElementByRank(zsl,start+1); } while(rangelen--) { //取rangelen个结点 serverAssertWithInfo(c,zobj,ln != NULL); ele = ln->obj; addReplyBulk(c,ele); //响应键名 if (withscores) addReplyDouble(c,ln->score); //响应键值 ln = reverse ? ln->backward : ln->level[0].forward; //设置下一个结点 } ...... } /* Finds an element by its rank. The rank argument needs to be 1-based. */ zskiplistNode* zslGetElementByRank(zskiplist *zsl, unsigned long rank) { zskiplistNode *x; unsigned long traversed = 0; //当前名次 int i; x = zsl->header; //头结点, 从头结点的下一个结点遍历 for (i = zsl->level-1; i >= 0; i--) { //从高层到低层链表遍历 while (x->level[i].forward && (traversed + x->level[i].span) <= rank) //如果有下一个结点,且下一个结点的名次<=rank { traversed += x->level[i].span; x = x->level[i].forward; } if (traversed == rank) { //找到对应名次的结点 return x; } } return NULL; }
zslGetElementByRank()时间复杂度理想值 = log(n)
...
以上是关于redis-zset数据结构探索的主要内容,如果未能解决你的问题,请参考以下文章