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

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

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

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,先判断高位再判断低位,所以没有问题。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值