当前位置: 首页 > article >正文

【redis】zset有序集合详解

zset有序集合详解

    • 一、zset有序集合的介绍
    • 二、zset有序集合的常用指令
      • 2.1 ZADD
      • 2.2 ZCARD
      • 2.3 ZCOUNT
      • 2.4 ZRANGE
      • 2.5 ZREVRANGE
      • 2.6 ZRANGEBYSCORE
      • 2.7 ZPOPMAX
      • 2.8 BZPOPMAX
      • 2.9 ZPOPMIN
      • 2.10 BZPOPMIN
      • 2.11 ZRANK
      • 2.12 ZREVRANK
      • 2.13 ZSCORE
      • 2.14 ZREM
      • 2.15 ZREMRANGEBYRANK
      • 2.16 ZREMRANGEBYSCORE
      • 2.17 ZINCRBY
      • 2.18 ZINTERSTORE
      • 2.19 ZUNIONSTORE
    • 三、set有序集合命令小结
    • 四、内部编码
      • 4.1压缩列表
      • 4.2跳表
    • 五、应用场景

一、zset有序集合的介绍

有序集合相对于字符串、列表、哈希、集合来说会有⼀些陌⽣。它保留了集合不能有重复成员的特点,但与集合不同的是,有序集合中的每个元素都有⼀个唯⼀的浮点类型的分数(score)与之关联,这使得有序集合中的元素是可以维护有序性的,但这个有序不是⽤下标作为排序依据⽽是⽤这个分数。例如:

在这里插入图片描述
有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利⽤有序集合,可以帮助我们在实际开发中解决很多问题。有序集合中的元素是不能重复的,但分数允许重复。类⽐于⼀次考试之后,每个⼈⼀定有⼀个唯⼀的分数,但分数允许相同

二、zset有序集合的常用指令

2.1 ZADD

添加或者更新指定的元素以及关联的分数到 zset 中,分数应该符合 double 类型,+inf/-inf 作为正负极限也是合法的

语法:

ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]

ZADD 的相关选项说明:

  • XX:仅仅⽤于更新已经存在的元素,不会添加新元素
  • NX:仅⽤于添加新元素,不会更新已经存在的元素
  • CH:默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会包含本次更新的元素的个数
  • INCR:此时命令类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数

返回值:本次添加成功的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 'one'
(integer) 1
127.0.0.1:6379> zadd key 2 'two'
(integer) 1
127.0.0.1:6379> zrange key 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
127.0.0.1:6379> zadd key 10 one 20 two 30 three
(integer) 1
127.0.0.1:6379> zrange key 0 -1 withscores
1) "one"
2) "10"
3) "two"
4) "20"
5) "three"
6) "30"

2.2 ZCARD

获取⼀个 zset 的基数(cardinality),即 zset 中的元素个数

语法:

ZCARD key

返回值:zset 内的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 'one' 2 'two'
(integer) 2
127.0.0.1:6379> zcard key
(integer) 2

2.3 ZCOUNT

返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,可以通过(排除

语法:

ZCOUNT key min max

返回值:满⾜条件的元素列表个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zcount key 1 3
(integer) 3
127.0.0.1:6379> zcount key (1 (3
(integer) 1

2.4 ZRANGE

返回指定区间⾥的元素,分数按照升序。带上 WITHSCORES 可以把分数也返回

语法:

ZRANGE key start stop [WITHSCORES]

返回值:区间内的元素列表

使用样例:

127.0.0.1:6379> zadd key 1 'one'
(integer) 1
127.0.0.1:6379> zadd key 2 'two'
(integer) 1
127.0.0.1:6379> zrange key 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"

2.5 ZREVRANGE

返回指定区间⾥的元素,分数按照降序。带上 WITHSCORES 可以把分数也返回

语法:

ZREVRANGE key start stop [WITHSCORES]

返回值:区间内的元素列表

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrevrange key 0 -1 withscores
1) "three"
2) "3"
3) "two"
4) "2"
5) "one"
6) "1"

2.6 ZRANGEBYSCORE

返回分数在 min 和 max 之间的元素,默认情况下,min 和 max 都是包含的,可以通过 ( 排除

语法:

ZRANGEBYSCORE key min max [WITHSCORES]

返回值:区间内的元素列表

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrangebyscore key 1 3
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zrangebyscore key (1 (3
1) "two"

2.7 ZPOPMAX

删除并返回分数最⾼的 count 个元素

语法:

ZPOPMAX key [count]

返回值:分数和元素列表

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zpopmax key 3
1) "three"
2) "3"
3) "two"
4) "2"
5) "one"
6) "1"

2.8 BZPOPMAX

ZPOPMAX 的阻塞版本 ,如果没有元素那么就会阻塞timeout秒等待元素到来,如果没有元素到来那么就返回nil,否则返回到来的元素

语法:

BZPOPMAX key [key ...] timeout

返回值:元素列表

使用样例:

127.0.0.1:6379> zadd key 3 three
(integer) 1
127.0.0.1:6379> bzpopmax key 2
1) "key"
2) "three"
3) "3"
127.0.0.1:6379> bzpopmax key 2
(nil)
(2.02s)

2.9 ZPOPMIN

删除并返回分数最低的 count 个元素

语法:

ZPOPMIN key [count]

返回值:分数和元素列表

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zpopmin key
1) "one"
2) "1"
127.0.0.1:6379> zpopmin key
1) "two"
2) "2"

2.10 BZPOPMIN

删除并返回分数最低的 count 个元素

语法:

ZPOPMIN key [count]

返回值:分数和元素列表

使用样例:

127.0.0.1:6379> zadd key 3 three
(integer) 1
127.0.0.1:6379> bzpopmin key 2
1) "key"
2) "three"
3) "3"
127.0.0.1:6379> bzpopmin key 2
(nil)
(2.04s)

2.11 ZRANK

返回指定元素的排名,升序

语法:

ZRANK key member

返回值:升序排名

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrank key two
(integer) 1
127.0.0.1:6379> zrank key three
(integer) 2
127.0.0.1:6379> zrank key one
(integer) 0

2.12 ZREVRANK

返回指定元素的排名,降序

语法:

ZREVRANK key member

返回值:降序排名

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrevrank key one
(integer) 2
127.0.0.1:6379> zrevrank key two
(integer) 1
127.0.0.1:6379> zrevrank key three
(integer) 0

2.13 ZSCORE

返回指定元素的分数

语法:

ZSCORE key member

返回值:分数

使用样例:

127.0.0.1:6379> zadd key 1 one
(integer) 1
127.0.0.1:6379> zscore key one
"1"

2.14 ZREM

删除指定的元素

语法:

ZREM key member [member ...]

返回值:本次操作删除的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrem key one two three
(integer) 3
127.0.0.1:6379> zrange key 0 -1
(empty array)

2.15 ZREMRANGEBYRANK

按照排序,升序删除指定范围的元素,左闭右闭

语法:

ZREMRANGEBYRANK key start stop

返回值:本次操作删除的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zremrangebyrank key 0 1
(integer) 2
127.0.0.1:6379> zrange key 0 -1
1) "three"

2.16 ZREMRANGEBYSCORE

按照分数删除指定范围的元素,左闭右闭

语法:

ZREMRANGEBYSCORE key min max

返回值:本次操作删除的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zremrangebyscore key 2 3
(integer) 2
127.0.0.1:6379> zrange key 0 -1
1) "one"

2.17 ZINCRBY

为指定的元素的关联分数添加指定的分数值

语法:

ZINCRBY key increment member

返回值:增加后元素的分数

使用样例:

127.0.0.1:6379> zadd key 1 one
(integer) 1
127.0.0.1:6379> zincrby key 2 one
"3"
127.0.0.1:6379> zrange key 0 1 withscores
1) "one"
2) "3"

2.18 ZINTERSTORE

求出给定有序集合中元素的交集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数

语法:

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
  • numkeys:表示比较多少个集合
  • weights:表示权重,默认值为1

返回值:⽬标集合中的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two
(integer) 2
127.0.0.1:6379> zadd key1 1 one 3 three
(integer) 2
#得到的分数 = key * 2 + key1 * 3
127.0.0.1:6379> zinterstore key2 2 key key1 weights 2 3
(integer) 1
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "one"
2) "5"

2.19 ZUNIONSTORE

求出给定有序集合中元素的并集并保存进⽬标有序集合中,在合并过程中以元素为单位进⾏合并,元素对应的分数按照不同的聚合⽅式和权重得到新的分数

语法:

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight[weight ...]] [AGGREGATE <SUM | MIN | MAX>]
  • numkeys:表示比较多少个集合
  • weights:表示权重,默认值为1

返回值:⽬标集合中的元素个数

使用样例:

127.0.0.1:6379> zadd key 1 one 2 two
(integer) 2
127.0.0.1:6379> zadd key1 1 one 3 three
(integer) 2
#得到的分数 = key * 2 + key1 * 3
127.0.0.1:6379> zunionstore key2 2 key key1 weights 2 3
(integer) 3
127.0.0.1:6379> zrange key2 0 -1 withscores
1) "two"
2) "4"
3) "one"
4) "5"
5) "three"
6) "9"

三、set有序集合命令小结

命令时间复杂度
zadd key score member [score member …]O(k * log(n)),k 是添加成员的个数,n 是当前有序集合的元素个数
zcard keyO(1)
zscore key memberO(1)
zrank key member zrevrank key memberO(log(n)),n 是当前有序集合的元素个数
zrem key member [member …]O(k * log(n)),k 是删除成员的个数,n 是当前有序集合的元素个数
zincrby key increment memberO(log(n)),n 是当前有序集合的元素个数
zrange key start end [withscores] zrevrange key start end [withscores]O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数
zrangebyscore key min max [withscores] zrevrangebyscore key max min [withscores]O(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数
zcountO(log(n)),n 是当前有序集合的元素个数
zremrangebyrank key start endO(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数
zremrangebyscore key min maxO(k + log(n)),k 是获取成员的个数,n 是当前有序集合的元素个数
zinterstore destination numkeys key [key …]O(n * k) + O(m * log(m)),n 是输⼊的集合最⼩的元素个数, k 是集合个数, m 是⽬标集合元素个数
zunionstore destination numkeys key [key …]O(n) + O(m * log(m)),n 是输⼊集合总元素个数,m 是⽬标集合元素个数

四、内部编码

有序集合类型的内部编码有两种:

  • ziplist(压缩列表):当有序集合的元素个数⼩于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都⼩于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会⽤ ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使⽤。

  • skiplist(跳表):当 ziplist 条件不满⾜时,有序集合会使⽤ skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降

  1. 使用ziplist压缩列表的条件:

当 Zset 存储的元素数量小于 zset-max-ziplist-entries 的值,且所有元素的最大长度小于 zset-max-ziplist-value 的值时,Redis 会选择使用压缩列表作为底层实现。压缩列表占用的内存较少,但是在需要修改数据时,可能需要对整个压缩列表进行重写,性能较低

  1. 使用skiplist跳表的条件:

当 Zset 存储的元素数量超过 zset-max-ziplist-entries 的值,或者任何元素的长度超过 zset-max-ziplist-value 的值时,Redis 会将底层结构从压缩列表转换为跳跃表。跳跃表的查找和修改数据的性能较高,但是占用的内存也较多

4.1压缩列表

压缩列表是一种为节省内存而设计的特殊编码结构,它将所有的元素和分数紧凑地存储在一起。这种方式的优点是占用内存少,但是在需要修改数据时,可能需要对整个压缩列表进行重写,性能较低。当 Zset 存储的元素数量较少,且元素的字符串长度较短时,Redis 会选择使用压缩列表作为底层实现。

一个压缩列表的结构如下:

在这里插入图片描述

在 Zset 中,每个元素和它的分数都会作为一个独立的元素存储在压缩列表中,元素和分数会交替存储,即第一个元素是成员,第二个元素是分数,第三个元素是成员,第四个元素是分数,以此类推

4.2跳表

跳跃表是一种可以进行快速查找的有序数据结构,它通过维护多级索引来实现快速查找。这种方式的优点是查找和修改数据的性能较高,但是占用的内存也较多。当 Zset 存储的元素数量较多,或者元素的字符串长度较长时,Redis 会选择使用跳跃表作为底层实现

跳表基本结构:

// 跳表节点结构  
typedef struct zskiplistNode {  
    sds ele;          // 元素值  
    double score;     // 分数  
    struct zskiplistNode *backward;  // 后退指针  
    struct zskiplistLevel {  
        struct zskiplistNode *forward;  // 前进指针  
        unsigned long span;  // 跨度  
    } level[];  // 层级数组  
} zskiplistNode;  

// 跳表头结构  
typedef struct zskiplist {  
    struct zskiplistNode *header, *tail;  // 头尾节点  
    unsigned long length;  // 长度  
    int level;  // 最大层数  
} zskiplist;

在这里插入图片描述

跳跃表的查找、插入和删除操作的时间复杂度都是 O(logN),其中 N 是跳跃表中的元素数量。这使得跳跃表在处理大量数据时具有很高的性能。跳表在链表的基础上增加了多级索引,通过多级索引位置的跳跃,实现了快速查找元素

五、应用场景

Redis 的 Zset(有序集合)类型在许多场景中都非常有用,以下是一些常见的应用场景:

  1. 排行榜:Zset 非常适合用于实现各种排行榜。例如,你可以将用户的 ID 作为元素,用户的分数作为分数,然后使用 Zset 来存储和排序所有用户的分数。你可以很容易地获取到分数最高的用户,或者获取到任何用户的排名。

  2. 带权重的队列:Zset 可以用于实现带权重的队列。例如,你可以将任务作为元素,任务的优先级作为分数,然后使用 Zset 来存储和排序所有的任务。你可以很容易地获取到优先级最高的任务,或者按优先级顺序执行任务。

  3. 延时队列:你可以将需要延时处理的任务作为元素,任务的执行时间作为分数,然后使用 Zset 来存储和排序所有的任务。你可以定期扫描 Zset,处理已经到达执行时间的任务

  4. 用户的点赞数:将用户的id作为元素,用户的点赞数作为分数,这样就可以实现用户点赞数的增长


http://www.kler.cn/a/412188.html

相关文章:

  • 计算机网络习题解答--个人笔记(未完)
  • 新版:微信小程序跳转到任意小程序指定页面
  • 【联表查询中的隐蔽 bug】
  • 网易博客旧文-----安卓界面代码例子研究(一)
  • UE5材质Texture Sample 节点的基本概念
  • 数据结构 ——— 快速排序的时间复杂度以及规避最坏情况的方法
  • SlickGrid复选框
  • 前端-Git
  • Linux高阶——1123—服务器基础服务器设备服务器基础能力
  • 多商户系统推动旅游业数字化升级与创新,定制化旅游促进市场多元化发展
  • Jackson库中JsonInclude的使用
  • 使用 Vue.js 创建一个简单的待办事项应用
  • QT QVerticalSpacer控件 全面详解
  • 16 —— Webpack多页面打包
  • 企业OA管理系统:Spring Boot技术深度解析
  • 自研芯片逾十年,亚马逊云科技Graviton系列芯片全面成熟
  • 景联文科技:高质量数据采集标注服务引领AI革新
  • Spring Boot Web应用开发:数据访问
  • 短信发送业务
  • 0基础学前端系列 -- 深入理解 HTML 布局