Redis从入门到精通(10):redis的sorted_set数据类型详解

Prunella ·
更新时间:2024-11-10
· 747 次阅读

前面提到的几种数据类型都各有特点,但是如果想对数据进行排序却做不到,想要数据能够按照某种特色进行排序,需要用到一种新类型,sorted_set。

我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。

文章目录sorted_set数据类型常用操作注意事项实际案例 sorted_set数据类型

在前面set的基础上,对每个元素增加一个score关键字,然后按照score的内容去进行排序。score关键字的内容可以选择显示或者不显示。

常用操作

更多操作可以通过help @sorted_set来查看

添加数据:

zadd key score1 member1 [score2 member2 …] 127.0.0.1:6380> zadd age 18 xiaofu 35 james 100 kobe (integer) 3 127.0.0.1:6380>

需要注意的是对sorted_set中的元素重新利用zadd来赋值一个新的score的时候,会返回0,但是却赋值成功了。可能是因为类似set类型,不允许有重复的元素。

127.0.0.1:6380> zadd age 40 xiaofu (integer) 0

查看数据:

zrange key start stop [withscores] zrevrange key start stop [withscores]

一个是按照从小到大的顺序,另一个是反向。默认是不显示score内容的,如果带上withscores关键字就会显示score。因为有顺序,就会有索引的概念,就跟前面的list数据类型一样,startstop分别表示开始和结束的索引,从0开始,-1表示最后一位。

127.0.0.1:6380> zrange age 0 -1 1) "james" 2) "xiaofu" 3) "kobe" 127.0.0.1:6380> zrange age 0 -1 withscores 1) "james" 2) "35" 3) "xiaofu" 4) "40" 5) "kobe" 6) "100"

获取最大值

127.0.0.1:6380> zrevrange age 0 0 withscores 1) "kobe" 2) "100" 127.0.0.1:6380>

删除数据

zrem key member [member …] 127.0.0.1:6380> zrem age kobe (integer) 1 127.0.0.1:6380> zrevrange age 0 -1 withscores 1) "xiaofu" 2) "43" 3) "james" 4) "35" 127.0.0.1:6380>

既然主要是根据score的值来进行的排序,当然也可以做更多的操作

按照score的值进行条件获取

zrangebyscore key min max [WITHSCORES] [LIMIT offset count] zrevrangebyscore key min max [WITHSCORES] [LIMIT offset count]

这里的limit和mysql里面的功能一模一样

127.0.0.1:6380> zrange age 0 -1 withscores 1) "gigi" 2) "18" 3) "brown" 4) "20" 5) "james" 6) "35" 7) "xiaofu" 8) "43" 9) "kobe" 10) "99" 127.0.0.1:6380> zrangebyscore age 20 50 withscores 1) "brown" 2) "20" 3) "james" 4) "35" 5) "xiaofu" 6) "43" 127.0.0.1:6380> zrangebyscore age 20 50 withscores limit 0 2 1) "brown" 2) "20" 3) "james" 4) "35" 127.0.0.1:6380>

按照score的值去条件删除字段:

zremrangebyscore key min max zremrangebyrank key start stop
一个是按照score的值去查询然后删除,另一个是按照排列顺序利用索引下标去删除 127.0.0.1:6380> zrange age 0 -1 withscores 1) "gigi" 2) "18" 3) "brown" 4) "20" 5) "james" 6) "35" 7) "xiaofu" 8) "43" 9) "kobe" 10) "99" 127.0.0.1:6380> zremrangebyscore age 20 40 (integer) 2 127.0.0.1:6380> zrange age 0 -1 withscores 1) "gigi" 2) "18" 3) "xiaofu" 4) "43" 5) "kobe" 6) "99" 127.0.0.1:6380> 127.0.0.1:6380> zrange age 0 -1 withscores 1) "gigi" 2) "18" 3) "xiaofu" 4) "43" 5) "kobe" 6) "99" 127.0.0.1:6380> zremrangebyrank age 0 1 (integer) 2 127.0.0.1:6380> zrange age 0 -1 withscores 1) "kobe" 2) "99" 127.0.0.1:6380>

统计元素个数:

zcard key zcount key min max
一个是统计全部,另一个是根据score的值统计在区间内的元素个数 127.0.0.1:6380> zrange age 0 -1 withscores 1) "gigi" 2) "18" 3) "davis" 4) "20" 5) "james" 6) "35" 7) "xiaofu" 8) "40" 9) "kobe" 10) "99" 127.0.0.1:6380> zcard age (integer) 5 127.0.0.1:6380> zcount age 15 35 (integer) 3 127.0.0.1:6380>

类似于set的集合操作:

ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
默认情况下是对相同元素的score进行求和处理,也可以修改为最小值或者最大值 127.0.0.1:6380> zadd s1 40 aa 50 bb 60 cc (integer) 3 127.0.0.1:6380> zadd s2 45 aa 55 bb 70 dd (integer) 3 127.0.0.1:6380> zadd s3 50 aa 60 bb 80 dd (integer) 3 127.0.0.1:6380> zinterstore ss 3 s1 s2 s3 (integer) 2 127.0.0.1:6380> zrange ss 0 -1 withscores 1) "aa" 2) "135" 3) "bb" 4) "165" 127.0.0.1:6380> 127.0.0.1:6380> zinterstore ss 3 s1 s2 s3 aggregate max (integer) 2 127.0.0.1:6380> zrange ss 0 -1 withscores 1) "aa" 2) "50" 3) "bb" 4) "60" 127.0.0.1:6380> 127.0.0.1:6380> zunionstore sss 3 s1 s2 s3 (integer) 4 127.0.0.1:6380> zrange sss 0 -1 1) "cc" 2) "aa" 3) "dd" 4) "bb" 127.0.0.1:6380> zrange sss 0 -1 withscores 1) "cc" 2) "60" 3) "aa" 4) "135" 5) "dd" 6) "150" 7) "bb" 8) "165" 127.0.0.1:6380>

某些场景下,例如电影热度榜单,明星热度榜单等,不仅会显示排序的结果还会显示索引。

获取数据对应的索引:

zrank key member zrevrank key member 127.0.0.1:6380> zadd scores 100 a 87 b 60 c 76 d (integer) 4 127.0.0.1:6380> zrank scores b (integer) 2 127.0.0.1:6380> zrevrank scores b (integer) 1 127.0.0.1:6380>

需要注意这里显示的是索引,比真正的排名差了1

获取和增加score:

zscore key member zincrby key increment member 127.0.0.1:6380> zscore scores c "60" 127.0.0.1:6380> zincrby scores 1 c "61" 127.0.0.1:6380> zscore scores c "61" 127.0.0.1:6380> 注意事项 如果是浮点型的score,存储结构是双精度。需要小心浮点型数据精度丢失的问题,可以参考我的另一篇博客《浮点型数据精度丢失实例详解》 如前面提到的,因为是基于set结构的,所以不能有重复的元素。如果对已存在的元素重新添加不同的score,会返回执行失败,但是score会被新的值覆盖 实际案例 时效性任务管理

例如视频网站会员过期,或者微信群投票过期,微信中历史图片过期等等。这种场景利用前面提到的ttl也是可以做得到,这里我们尝试用sorted_set来完成这个功能。

思路:将用户的id存储到sorted_set中,到期时间线的unix时间戳存储为score,这样最先到期的就排在最上面。每次记录最上面的时间戳,当和现在的时间戳相同时就删除该用户的记录。没有记录的用户就提示过期。

实际的操作也比较简单,这里主要是想引出redis中显示时间戳的函数time

127.0.0.1:6380> time 1) "1581783416" 2) "950338" 127.0.0.1:6380>

其中第一个数字是秒级别的时间戳,基本上就够用了

带权重的消息或任务队列

前面学习list数据类型的时候,可以很方便的制作一个消息或者任务队列。但是那个只能按照时间顺序去处理,如果要加权重的会只能用到这里讲的sorted_set。

思路:将任务的权重放在score当中进行排序,利用zpopmax或者zpopmin去获取并移除最高权重的任务即可

127.0.0.1:6380> zadd tasks 1 aa 3 bb 4 cc 1 dd 2 ee 4 ff (integer) 6 127.0.0.1:6380> zrange tasks 0 -1 withscores 1) "aa" 2) "1" 3) "dd" 4) "1" 5) "ee" 6) "2" 7) "bb" 8) "3" 9) "cc" 10) "4" 11) "ff" 12) "4" 127.0.0.1:6380> zpopmin tasks 1) "aa" 2) "1" 127.0.0.1:6380> zrange tasks 0 -1 withscores 1) "dd" 2) "1" 3) "ee" 4) "2" 5) "bb" 6) "3" 7) "cc" 8) "4" 9) "ff" 10) "4" 127.0.0.1:6380>

假设所有多维度的权重要处理,例如部门A的权重高过部门B,但是部门主管的权重高过部门成员。这时候就可以将部门主管编号为100,普通员工编号为101,部门A编号为200,部门B编号为201,这样首先放行政级别再放部门即可,例如100200或者101200,先判断高位再判断低位,所以没有问题。

但是这种多维度的问题在设定数字的时候比较考验技巧,位数要相同,不然可能会发生错位比较的情况,同时不同维度的设计也是个技术活。


作者:T型人小付



sorted set Redis

需要 登录 后方可回复, 如果你还没有账号请 注册新账号