Redis ZSet (5)

Stella981
• 阅读 446

存储类型

ZSet集合基本与Set相同,只是多了一个数值类型属性score,score相同时,按照Key的ASC码排序。

Redis ZSet (5)

数据结构对比

数据结构

是否允许重复

是否有序

有序实现方式

List

索引下标

Set

ZSet

score属性

# 无序插入
127.0.0.1:6379> zadd lzset 20 c 30 d 10 b 1 a
(integer) 4

# 获取数据是有序的
127.0.0.1:6379> zrange lzset 0 -1 withscores
1) "a"
2) "1"
3) "b"
4) "10"
5) "c"
6) "20"
7) "d"
8) "30"

存储(实现)原理

同时满足以下条件时使用ziplist编码:

  • 元素数量小于128个
  • 所有member的长度都小于64字节

在ziplist的内部,按照score排序递增来存储。插入的时候要移动之后的数据。

redis.conf配置

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

超过阈值之后,使用skiplist+dict存储。

什么是skiplist?

下边是普通的有序列表 Redis ZSet (5)

在这样一个链表中,如果我们要查找某个数据,那么需要从头开始逐个进行比较,直到找到包含数据的那个节点,或者找到第一个比给定数据大的节点为止(没找到)。也就是说,时间复杂度为O(n)。同样,当我们要插入新数据的时候,也要经历同样的查找过程,从而确定插入位置。

而二分查找法只适用于有序数组,不适用于链表。

假如我们每相邻两个节点增加一个指针(或者理解为有三个元素进入了第二层),让指针指向下下个节点。

Redis ZSet (5)

这样所有新增加的指针连成了一个新的链表,但它包含的节点个数只有原来的一半(上图中是6,18,40)。在插入一个数据的时候,决定要放到那一层,取决于一个算法(在redis中t_zset.c有一个zslRandomLevel这个方法)。

现在当我们想查找数据的时候,可以先沿着这个新链表进行查找。当碰到比待查数据大的节点时,再回到原来的链表中的下一层进行查找。比如,我们想查找34,查找的路径是沿着下图中标红的指针所指向的方向进行的:

Redis ZSet (5)

  1. 34首先和6(lev2)比较,再和18比较,比它们都大,继续向后比较。
  2. 但34和40比较的时候,比40要小,因此回到下面的链表(原链表lev1),与23比较。
  3. 34比23要大,沿下面的指针继续向后和40比较。34比40小,说明待查数据34在原链表中不存在

在这个查找过程中,由于新增加的指针,我们不再需要与链表中每个节点逐个进行比较了。需要比较的节点数大概只有原来的一半。这就是跳跃表。

为什么不用AVL树或者红黑树?因为skiplist更加简洁。
/* ZSETs use a specialized version of Skiplists */
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;

随机获取层数的函数:(源码:t_zset.c)

/* Returns a random level for the new skiplist node we are going to create.
 * The return value of this function is between 1 and ZSKIPLIST_MAXLEVEL
 * (both inclusive), with a powerlaw-alike distribution where higher
 * levels are less likely to be returned. */
int zslRandomLevel(void) {
    int level = 1;
    while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

适用于做排行榜,或者做简单队列优先级

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
Github标星5300+,专门为程序员开发文档开源管理系统,我粉了
!(https://oscimg.oschina.net/oscnet/a11909a041dac65b1a36b2ae8b9bcc5c432.jpg)码农那点事儿关注我们,一起学习进步!(https://oscimg.oschina.net/oscnet/f4cce1b7389cb00baaab228e455da78d0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这