Redis中的zset类型详解

 更新时间:2023年08月24日 10:19:09   作者:指挥部在下面  
有序集合zset保留了set集合不能有重复成员的特点,但与set集合不同的是,zset的每个member都有一个唯一的浮点数类型的分数score与之关联,这篇文章主要介绍了Redis的zset类型,需要的朋友可以参考下

什么是zset

有序集合zset保留了set集合不能有重复成员的特点,但与set集合不同的是,zset的每个member都有一个唯一的浮点数类型的分数score与之关联。依据每个member的score进行排序。结构如下图所示:

image.png

有序集合中的元素是不能重复的,但分数允许重复

常用命令

zadd

添加或更新指定元素以及关联的分数到zset中,分数是double类型语法: zadd key [nx|xx] [gt|lt] [ch] [incr] score member [score member...]

  • nx:仅用于添加新元素,不能更新已经存在的元素
  • xx:仅用于更新已经存在的元素,不能添加新元素
  • gt:greater than 只能更新已经存在并且分数比现在的分数高的元素,能正常添加元素
  • lt:less than 只能更新已经存在并且分数比现在分数低的元素,能正常添加元素
  • ch:默认情况,zadd返回的是本次添加元素的个数,但指定这个选项后,还会包含本次更新的元素的个数
  • incr:将元素的分数加上指定的分数,并且只能指定一个元素和分数

我使用的版本是redis5,在redis5中不支持 gt/lt操作

时间复杂度:O(logN)

由于zset是有序结构,要求新增的元素,要放到合适的位置上即找位置的过程,zset内部使用跳表的数据结构,可以达到O(logN)

image.png

:::dangerzset中的member和score不是键值对的关系,而是“pair”的关系,可以通过member找到score,也可以通过score找到member:::

zrange

查看zset中元素详情语法: zrange key start stop 时间复杂度:O(logN+M)

首先根据下标找到边界值,找元素O(logN),从start位置开始遍历到stop位置,O(m)

image.png

redis内部存储数据是按照二进制存储,所以redis服务器不负责“字符编码”,因此需要redis客服端支持

添加 withscores 能查看每个元素对应分数

image.png

zset内部默认是按照升序的方式来排列的

zrevrange

返回指定区间元素,分数按降序排列,带上 withscores 可以将分数加上语法: zrevrange key start stop [withscores] 时间复杂度:O(logN+M)

image.png

zcard

查看一共有几个元素语法: zcard key 时间复杂度:O(1)

image.png

zcount

根据给定分数区间查找有几个元素语法: zcount key min max 闭区间时间复杂度:O(logN)

先根据min找到对应元素,再根据max找到对应元素,而查找元素的时间复杂度是O(logN),由于zset内部记录每个元素的“次序”,可以直接把max对应元素的次序减去min对应元素的次序即可,不需要进行遍历。

image.png

使用 ( 表示开区间

image.png

min和max可以写成浮点数,浮点数中inf表示无穷大,-inf表示负无穷大

image.png

zrangebyscore

返回分数在min和max之间的元素语法: zrangebyscore key min max [withscores] 时间复杂度:O(logN+M)

image.png

在redis6以后该命令被废弃,将功能合并到zrange中

zpopmax

删除并返回分数最高的count个元素,类似topk问题语法: zpopmax key [count] 时间复杂度:O(logN*M)

删除M个元素,查找一个元素时间复杂度为O(logN)

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

image.png

bzpopmax

zpopmax的阻塞版本语法: bzpopmax key [key...] timeout 时间复杂度:O(logN)返回值:返回元素列表

image.png

zpopmin

删除并返回分数最低的count个元素语法: zpopmin key [count] 时间复杂度:O(logN*M)返回值:返回分数和元素列表

image.png

bzpopmin

zpopmin的阻塞版本语法: bzpopmin key [key...] timeout 时间复杂度:O(logN)返回值:返回元素列表

image.png

zrank

返回指定元素的次序,按升序排语法: zrank key member 时间复杂度:O(logN)返回值:返回对应次序/下标

image.png

zrevrank

zrank的降序版本语法: zrevrank key member 时间复杂度:O(logN)返回值:返回对应元素次序/下标

image.png

zscore

返回指定元素的分数语法: zscore key member 时间复杂度:O(1)

在前面的命令中根据member找元素的时间复杂度都是O(logN),但是这里redis牺牲空间,换取时间做了特定的优化

image.png

zrem

删除指定元素语法: zrem key member [member...] 返回值:分数

image.png

zremrangebyrank

根据下标表示的范围进行删除,闭区间语法: zremrangebyrank key start stop 时间复杂度:O(logN+M)

查找位置只需一次即可,然后删除M个元素

返回值:返回删除的个数

image.png

zremrangebyscore

删除对应的分数范围内的元素语法: zremrangebyscore key min max 时间复杂度:O(logN+M)返回值:返回删除个数

image.png

zincrby

修改元素的分数,并保持整个有序集合仍然是升序的语法: zincrby key increment member 时间复杂度:O(logN)返回值:增加后元素的分数

image.png

zinterstore

将给定有序集合中元素的交集并保持到目标有序集合中语法: zinterstore destination numkeys key [key...] [weights weight [weight ...]] [aggregate <sum|min|max>]

  • destination:把结果存储到这个key
  • numkeys:整数,描述后续有几个key参与交集运行
  • weights: 权重,有序集合带有分数,此处指定的权重,相当于一个系数,会乘于当前的分数
  • aggregate:求并集时相同的元素的分数是相加/取最小/取最大,默认是相加

时间复杂度:O(NK)+O(Mlog(M)) -> O(M*logM)

N:输入若干个有序集合中,元素最少的个数
K:有几个有序集合
M:最终有序集合的元素个数
k一般不会太大,可以看作1,N和M接近,同一个数量级。
所以O(NK)+O(Mlog(M))->O(M)+O(Mlog(M))-> O(MlogM)

image.png

c:300.5+102=35
a:100.5+202=45

zunionstore

将给定有序集合中元素的并集并保存进目标有序集合中语法: zunionstore destination numkeys key [key...] [weights weight [weight...]][aggregate <sum|min|max>] 用法和 zinterstore 一致

image.png

内部编码

如果有序集合中的元素个数较少,或者各个元素体积较小使用 ziplist 来存储,如果当前元素个数比较多,或者各个元素体积非常大使用 skiplist 存储

image.png

应用场景

最关键的应用场景就是排行榜系统,例如微博热搜,游戏天梯排行,成绩排行

1.游戏天梯排汗

使用zset将玩家信息和对应分数存入即可,就会自动生成一个排行榜,可以使用 zrevrange 取出前几名玩家。当分数发生改变,可以使用 zincrby 修改分数,排行顺序能自动调整。

2.微博热搜

微博热搜需要考虑到浏览量,点赞量,转发量,评论量等,需要使用权重 weights ,此时可以使用 zinterstore/zunionstore 按照加权的方式处理。可以将每个维度的数值放到有序集合中, member 就是微博id, score 就是各个维度的数值。通过 zinterstore/zunionstore 把上述有序集合按照约定的权重,进行集合间运算即可。

到此这篇关于Redis的zset类型的文章就介绍到这了,更多相关Redis zset类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis之sql缓存的具体使用

    Redis之sql缓存的具体使用

    本文主要介绍了Redis之sql缓存的具体使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Redis中Hash函数的12种用法详解

    Redis中Hash函数的12种用法详解

    在Redis中,Hash(哈希)类型 是存储对象属性的黄金方案,无论是用户信息、商品库存,还是配置参数,Hash都能以 O(1) 的时间复杂度 实现高效读写,本文将通过 12种Hash函数,结合 Java代码+Redis命令,带你从零到精通,需要的朋友可以参考下
    2025-09-09
  • Redis和数据库 数据同步问题的解决

    Redis和数据库 数据同步问题的解决

    这篇文章主要介绍了Redis和数据库 数据同步问题的解决操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 浅谈Redis中的缓存更新策略

    浅谈Redis中的缓存更新策略

    这篇文章主要介绍了浅谈Redis中的缓存更新策略,CacheAsidePatter是我们比较常用的缓存更新策略,其由缓存调用者在更新数据库时,在业务逻辑中设置缓存更新,需要的朋友可以参考下
    2023-08-08
  • 详解Redis中数值乱码的根本原因以及解决方式

    详解Redis中数值乱码的根本原因以及解决方式

    这篇文章给大家详细分析了Redis中数值乱码的根本原因以及解决方式,通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02
  • redis集群搭建_动力节点Java学院整理

    redis集群搭建_动力节点Java学院整理

    这篇文章主要介绍了redis集群搭建,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Linux系统下安装Redis数据库过程

    Linux系统下安装Redis数据库过程

    大家好,本篇文章主要讲的是Linux系统下安装Redis数据库过程,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • 为什么断电后Redis数据不会丢失

    为什么断电后Redis数据不会丢失

    Redis 作为一款内存数据库,被广泛使用于缓存,分布式锁等场景,那么假如断电或者因其他因素导致 Reids 服务宕机,在重启之后数据会丢失吗?本文就来介绍与一下
    2021-08-08
  • 基于Redis过期事件实现订单超时取消

    基于Redis过期事件实现订单超时取消

    这篇文章主要介绍了基于Redis过期事件实现订单超时取消,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • Redis全量复制与部分复制示例详解

    Redis全量复制与部分复制示例详解

    这篇文章主要给大家介绍了关于Redis全量复制与部分复制的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis爬虫具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08

最新评论