Redis存储⑥Redis五大数据类型之 Zset

news2025/2/13 8:31:21

目录

 1. Zset 有序集合

1.1 Zset 有序集合常见命令

zadd

zcard

zcount

zrange

zrevrange

zrangebyscore(弃用)

zpopmax

bzpopmax

zpopmin

bzpopmin

zrank

zrevrank

zscore

zrem

zremrangebyrank

zremrangebyscore

zincrby

1.2 Zset有序集合间操作

zinterstore

zunionstore

1.3 Zset命令小结和内部编码

1.4 Zset有序集合使用场景

本篇完。


 1. Zset 有序集合

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

Zset 的内部数据结构是跳表。

如下图所示,该有序集合显示了三国中的武将的武力。

有序集合:

        有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利用有序集合,可以帮助我们在实际开发中解决很多问题。

        有序集合中的元素是不能重复的,但分数允许重复。类比于一次考试之后,每个人一定有一个唯一的分数,但分数允许相同。

列表、集合、有序集合三者的异同点: 


1.1 Zset 有序集合常见命令

zadd

        添加或者更新指定的元素以及关联的分数到 zset 中,分数应该符合 double 类型,+inf/-inf 作为正负极限也是合法的。注意:负无穷大不是无穷小,负无穷大的绝对值和无穷大是一样的。

zadd的相关选项:

  • xx:仅仅用于更新已经存在的元素(member),不会添加新元素。

  • nx:仅用于添加新元素(member),不会更新已经存在的元素。

  • lt:仅当新分数小于当前分数时才更新现有元素,不会阻止添加新元素。

  • gt:仅当新分数大于当前分数时才更新现有元素,不会阻止添加新元素。

  • ch:默认情况下,zadd 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。

  • incr:此时命令类似 zincrby 的效果,将元素的分数加上指定的分数。此时只能指定一个元素和分数。

语法:zadd key [nx | xx] [gt | lt] [ch] [incr] score member [score member ...]

        member 和 score 称为是一个 "pair",类似于 C++ 里的 std::pair。不要把它们理解成 “键值对”(key - value pair),键值对中是有明确的 “角色区分”,一定是根据键 -> 值。而对于有序集合来说,既可以通过 member 找到对应的 score,也可以通过 score 找到匹配的 member。

命令有效版本:1.2.0 之后

时间复杂度:O(log(N))

返回值:返回新增成功的元素个数。

示例:

如果修改的分数影响到了之前的顺序,就会自动的移动元素位置,保持原有的升序顺序不变:


不存在才插入:


存在才插入:


返回更新元素的个数:


给元素加上指定分数:


zcard

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

语法:zcard key 

命令有效版本:1.2.0 之后

时间复杂度:O(1)

返回值:zset 内的元素个数。

示例:


zcount

返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,如果不想要边界值,可以通过在边界值前加上 '(' 来排除。

语法:zcount key min max

命令有效版本:2.0.0 之后

时间复杂度:O(log(N))。先根据 min 找到对应的元素,再根据 max 找到对应的元素,两次都是 O(log(N))。实际上,Zset 内部会记录每个元素当前的 “排行” / “次序”,查询到元素就直接知道了元素所在的 “次序”(下标),就可以直接把 max 对应的元素次序和 min 对应的元素次序做减法即可。

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

示例:(注意最后括号的写法,与常见的不同)


zrange

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

语法:zrange key start stop [withscores]  。此处的 [start, stop] 为下标构成的区间,从 0 开始,支持负数。

命令有效版本:1.2.0 之后

时间复杂度:O(log(N)+M),N 是整个有序集合的元素个数,M 是 start - stop 区间内的元素个数。

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

示例:

        Redis 内部存储数据是按照二进制的方式存储的,意味着 Redis 服务器是不负责字符编码的,所以要把二进制对回到汉字需要客户端支持:


zrevrange

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

备注:这个命令可能在 6.2.0 之后废弃,并且功能合并到 ZRANGE 中。

语法:zrevrangekey start stop [withscores] 

命令有效版本:1.2.0 之后

时间复杂度:O(log(N)+M)

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

示例:


zrangebyscore(弃用)

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

备注:这个命令可能在 6.2.0 之后废弃,并且功能合并到 ZRANGE 中。

语法:zrangebyscore key min max [withscore]  

命令有效版本:1.0.5 之后

时间复杂度:O(log(N)+M)

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

示例:


zpopmax

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

语法:zpopmax key [count]

命令有效版本:5.0.0 之后

时间复杂度:O(log(N) * M),N 是有序集合的元素个数,M 表示 count,要删除的元素个数。

        既然是尾删,为什么不把最后一个元素的位置特殊标记一下,后续删除不久省却了查找过程,直接 O(1) 了吗?

        这个是有可能的,但是目前 Redis 并没有这么做。事实上,Redis 的源码中针对有序集合确实是记录了尾部的特定位置,但是在实际删除的时候并没有用上这个特性,而是直接调用了一个 “通用的删除函数”(给定一个 member 的值,进行查找,找到位置之后再删除)。(一些人认为此处是存在优化空间的)

返回值:分数和元素列表。

示例:

        如果存在多个元素分数相同(分数是主要因素,相同的情况下会按照 member 字符串的字典序来决定先后顺序),同时为最大值,那么 zpopmax 删除最大元素时,仍然只会删除其中一个元素。


bzpopmax

zpopmax 的阻塞版本。可以同时读多个有序集合。

语法:bzpopmax key [key ...] timeout。timeout 单位是 s,支持小数形式。

命令有效版本:

5.0.0 之后

时间复杂度:O(log(N)),删除最大值花费的时间。如果当前 BZPOPMAX 同时监听多个 key,假设 key 是 M 个,那么此时时间复杂度是 O(log(N) * M) 吗?每个这样的 key 上面都删除一次元素才需要 * M,而这里是从这若干个 key 中只删除一次。

返回值:元素列表。

示例:


zpopmin

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

语法:zpopmin key [count] 

命令有效版本:5.0.0 之后

时间复杂度:O(log(N) * M)

返回值:分数和元素列表。

示例:


bzpopmin

zpopmin 的阻塞版本。

语法:bzpopmin key [key ...] timeout

命令有效版本:5.0.0 之后

时间复杂度:O(log(N))

返回值:元素列表。

和bzpopmax阻塞效果类似,不做演示。


zrank

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

语法:zrank key member

命令有效版本:2.0.0 之后

时间复杂度:O(log(N))。zrank 查找元素的过程和 zcount是一样的。

返回值:排名。

示例:


zrevrank

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

语法:zrevrank key member 

命令有效版本:2.0.0 之后

时间复杂度:O(log(N))

返回值:排名。

示例:


zscore

返回指定元素的分数。

语法:zscore key member 

命令有效版本:1.2.0 之后

时间复杂度:O(1)。此处相当于 Redis 对于这样的查询操作做了特殊优化,付出了额外的空间代价。

返回值:分数。

示例:


zrem

删除指定的元素。

语法:zrem key member [member ...] 

命令有效版本:1.2.0 之后

时间复杂度:O(M*log(N))

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

示例:


zremrangebyrank

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

语法:zremrangebyrank key start stop  

命令有效版本:2.0.0 之后

时间复杂度:O(log(N)+M)

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

示例:


zremrangebyscore

按照分数删除指定范围的元素,左闭右闭,也可以使用 '(' 来排除边界值。

语法:zremrangebyscore key min max 

命令有效版本:1.2.0 之后

时间复杂度:O(log(N)+M)

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

示例:


zincrby

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

语法:zincrby key increment member

命令有效版本:1.2.0 之后

时间复杂度:O(log(N))

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

示例:

zincrby 不光会修改分数内容,也能同时移动元素位置,保证整个有序集合仍然是升序的。


1.2 Zset有序集合间操作

有序集合的交集操作:


zinterstore

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

        在有序集合中,member 是元素的本体,score 只是辅助排序的工具人。因此,在进行比较 “相同” 时,只要 member 相同即可。如果 member 相同,score 不同,进行交集合并之后的最终分数看 AGGREGATE 后面的属性。

语法:zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate <sum| min | max>]

numkeys 是一个整数,用来描述后续有几个 key 参与交集运算。

命令有效版本:2.0.0 之后

时间复杂度:O(N*K)+O(M*log(M)),N 是输入的有序集合中,最小的有序集合的元素个数;K 是输入了几个有序集合;M 是最终结果的有序集合的元素个数。

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

示例:


zunionstore

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

有序集合的并集操作:

语法:zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate <sum| min | max>]

命令有效版本:2.0.0 之后

时间复杂度:O(N)+O(M*log(M)) N 是输入的有序集合总的元素个数,M 是最终结果的有序集合的元素个数。

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

示例:


1.3 Zset命令小结和内部编码

有序集合命令:


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

  • ziplist(压缩列表):当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都小于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会用 ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。
  • skiplist(跳表):当 ziplist 条件不满足时,有序集合会使用 skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降。

简单来说,跳表是一个 “复杂链表”,查询元素的时间复杂度是 O(logN)。相比于树形结构,更适合按照范围获取元素。

1. 当元素个数较少且每个元素较小时,内部编码为 ziplist

2. 当元素个数超过 128 个,内部编码 skiplist

3. 当某个元素大于 64 字节时,内部编码 skiplist


1.4 Zset有序集合使用场景

        有序集合比较典型的使用场景就是排行榜系统。例如常见的网站上的热榜信息,榜单的维度可能是多方面的:按照时间、按照阅读量、按照点赞量。本例中我们使用点赞数这个维度,维护每天的热榜:

1. 添加用户赞数

例如用户 james 发布了一篇文章,并获得 3 个赞,可以使用有序集合的 zadd 和 zincrby 功能:

zadd user:ranking:2022-03-15 3 james

之后如果再获得赞,可以使用 zincrby:

zincrby user:ranking:2022-03-15 1 james

2. 取消用户赞数

        由于各种原因(例如用户注销、用户作弊等)需要将用户删除,此时需要将用户从榜单中删除掉,可以使用 zrem。例如删除成员 tom:

zrem user:ranking:2022-03-15 tom

3. 展示获取赞数最多的 10 个用户

此功能使用 zrevrange 命令实现:

zrevrangebyrank user:ranking:2022-03-15 0 9

4. 展示用户信息以及用户分数

        此功能将用户名作为键后缀,将用户信息保存在哈希类型中,至于用户的分数和排名可以使用 zscore 和 zrank 来实现。

hgetall user:info:tom
zscore user:ranking:2022-03-15 mike
zrank user:ranking:2022-03-15 mike

本篇完。

下一篇是Redis存储⑦其它数据类型+渐进式遍历+数据库管理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将Excel中的图片保存下载并导出

目录 效果演示 注意事项 核心代码 有需要将excel中的图片解析出来保存到本地的小伙子们看过来&#xff01;&#xff01;&#xff01; 效果演示 注意事项 仅支持xlsx格式&#xff1a;此方法适用于Office 2007及以上版本的.xlsx文件&#xff0c;旧版.xls格式无法使用。 图片名…

SQL注入之布尔和时间盲注,sqli-labs

实验环境&#xff1a; sqli-labs&#xff0c;小皮面板搭建&#xff0c;edge浏览器 apache&#xff1a;2.4.39&#xff0c;MySQL&#xff1a;5.7 PHP&#xff1a;5.39 Python&#xff08;pycharm2023&#xff09;:3 less-8 布尔盲注&#xff1a; 1.我这里是采用最简单的直接采…

基于云计算、大数据与YOLO设计的火灾/火焰目标检测

摘要&#xff1a;本研究针对火灾早期预警检测需求&#xff0c;采用在Kaggle平台获取数据、采用云计算部署的方式&#xff0c;以YOLO11构建模型&#xff0c;使用云计算服务器训练模型。经训练&#xff0c;box loss从约3.5降至1.0&#xff0c;cls loss从约4.0降至1.0&#xff0c;…

YOLO自定义数据集实现K折交叉验证——K-Fold Cross Validation

实现K折交叉验证&#xff08;K-Fold Cross Validation&#xff09;对于YOLO&#xff08;You Only Look Once&#xff09;自定义数据集的目标检测任务可以显著提升模型的可靠性和泛化能力。 1. 数据集准备 首先&#xff0c;你需要确保你的数据集符合YOLO的格式&#xff0c;具体…

go语言简单快速的按顺序遍历kv结构(map)

文章目录 需求描述用map实现按照map的key排序用二维切片实现用结构体实现 需求描述 在go语言中&#xff0c;如果需要对map遍历&#xff0c;每次输出的顺序是不固定的&#xff0c;可以考虑存储为二维切片或结构体。 假设现在需要在页面的下拉菜单中展示一些基础的选项&#xff…

【竞技宝】LOL-LPL:EDG3-0零封LNG

北京时间2月12日,英雄联盟LPL2025正在如火如荼的进行之中,昨日迎来LNG对阵EDG,以下是本场比赛的详细战报。 第一局: EDG:杰斯、赵信、维克托、女枪、芮尔 LNG:猴子、猪妹、飞机、韦鲁斯、布隆 首局比赛,EDG在蓝色方,LNG在红色方。阵容方面,EDG点出了杰斯、赵信、维克托、女枪…

在fedora41中安装钉钉dingtalk_7.6.25.4122001_amd64

在Fedora-Workstation-Live-x86_64-41-1.4中安装钉钉dingtalk_7.6.25.4122001_amd64.deb 到官网下载钉钉Linux客户端com.alibabainc.dingtalk_7.6.25.4122001_amd64.deb https://page.dingtalk.com/wow/z/dingtalk/simple/ddhomedownload#/ 一、直接使用dpkg命令安装deb包报错…

看期货用的指标,可以提示买卖点和K线转折变颜色的主图指标源码下载

A:MA(CLOSE,17)ABS(MA(CLOSE,17)-REF(MA(CLOSE,17),1)); B:MA(CLOSE,17)MA(CLOSE,17)-REF(MA(CLOSE,17),1); 分界线:IF(MA(CLOSE,17)<B,B,MA(CLOSE,17)),COLORFF00FF,LINETHICK2; 操作线:分界线-(EMA(C,3)-分界线),COLOR00FFFF,LINETHICK2; GUP:MA(C,5),COLORWHITE,LINE…

【PS 2022】Adobe Genuine Service Alert 弹出

电脑总是弹出Adobe Genuine Service Alert弹窗 1. 不关掉弹窗并打开任务管理器&#xff0c;找到Adobe Genuine Service Alert&#xff0c;并右键进入文件所在位置 2 在任务管理器中结束进程并将文件夹中的 .exe 文件都使用空文档替换掉 3. 打开PS不弹出弹窗&#xff0c;解决&a…

30天开发操作系统 第 20 天 -- API

前言 大家早上好&#xff0c;今天我们继续努力哦。 昨天我们已经实现了应用程序的运行, 今天我们来实现由应用程序对操作系统功能的调用(即API, 也叫系统调用)。 为什么这样的功能称为“系统调用”(system call)呢&#xff1f;因为它是由应用程序来调用(操作)系统中的功能来完…

蓝桥杯(B组)-每日一题(求最大公约数最小公倍数)

题目&#xff1a; 代码展现&#xff1a; #include<iostream> using namespace std; int main() {int m,n,x,y;cin>>m>>n;//输入两个整数int b;bm%n;//取余数xm;//赋值yn;while(b)//当余数不为0的时候{xy;//辗转相除求最小公约数yb;bx%y;}cout<<y<&…

arduino扩展:Arduino Mega 控制 32 个舵机(参考表情机器人)

参考&#xff1a;表情机器人中使用22个舵机的案例 引言 在电子制作与自动化控制领域&#xff0c;Arduino 凭借其易用性和强大的扩展性备受青睐。Arduino Mega 作为其中功能较为强大的一款开发板&#xff0c;具备丰富的引脚资源&#xff0c;能够实现复杂的控制任务。舵机作为常…

基于51单片机的门禁刷卡器proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1j0KAmH5pVGWZWRpT6p5hBg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

mapbox进阶,添加绘图扩展插件,裁剪线

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

19.4.6 读写数据库中的二进制数据

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 需要北风数据库的请留言自己的信箱。 北风数据库中&#xff0c;类别表的图片字段在【数据表视图】中显示为Bitmap Image&#xff1…

MapReduce到底是个啥?

在聊 MapReduce 之前不妨先看个例子&#xff1a;假设某短视频平台日活用户大约在7000万左右&#xff0c;若平均每一个用户产生3条行为日志&#xff1a;点赞、转发、收藏&#xff1b;这样就是两亿条行为日志&#xff0c;再假设每条日志大小为100个字节&#xff0c;那么一天就会产…

Winform自定义控件与案例 - 构建炫酷的自定义环形进度条控件

文章目录 1、控件效果2、案例实现1、代码实现2、代码解释3、使用示例 4、总结 1、控件效果 2、案例实现 1、代码实现 代码如下&#xff08;示例&#xff09;&#xff1a; using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; …

【SpringBoot苍穹外卖】debugDay03.5

1、AOP面向切面编程 1. Target(ElementType.METHOD) 作用&#xff1a;指定自定义注解可以应用的目标范围。 参数&#xff1a;ElementType 是一个枚举类&#xff0c;定义了注解可以应用的目标类型。 ElementType.METHOD 表示该注解只能用于方法上。 其他常见的 ElementType 值…

flink实时集成利器 - apache seatunnel - 核心架构详解

SeaTunnel&#xff08;原名 Waterdrop&#xff09;是一个分布式、高性能、易扩展的数据集成平台&#xff0c;专注于大数据领域的数据同步、数据迁移和数据转换。它支持多种数据源和数据目标&#xff0c;并可以与 Apache Flink、Spark 等计算引擎集成。以下是 SeaTunnel 的核心架…

视频理解新篇章:Mamba模型的探索与应用

人工智能咨询培训老师叶梓 转载标明出处 想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具&#xff08;限时免费&#xff09;。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Facto…