1. 首页
  2. redis实践

SortedSet如何实现多维度排序

说明:本次实践基于Redis版本3.2.11。

关于SortedSet

首先,我们都知道Redis的SortedSet是可以根据score进行排序的,以手机应用商店的热门榜单排序为例,根据下载量倒序排列,其简单用法如下:

  127.0.0.1:6379> zadd TopApp 12000000 wechat
    (integer) 1
    127.0.0.1:6379> zadd TopApp 8000000 taobao 10000000 alipay
    (integer) 2
    127.0.0.1:6379> ZREVRANGE TopApp 0 -1
    1) "wechat"
    2) "alipay"
    3) "taobao"

对SortedSet做一下简单总结:

  1. 默认升序排列,即通过命令ZRANGE实现;如果要按照降序排列,需要通过命令ZREVRANGE实现;
  2. 当score即得分一样时,按照字典顺序对member进行排序,字典排序用的是二进制,它比较的是字符串的字节数组,所以实际上是比较ASCII码。

简单用法介绍完后,接下来给出几种方案,介绍如何利用Redis实现多维度排序。同样的,还是以手机应用商店的热门榜单排序为例:首先按照APP的下载量倒序排序,如果下载量一样,则按照最后更新时间倒序排列。

方案1

介绍的第一个方案,并不需要依赖SortedSet,它的实现非常简单,但是需要产品做简单的妥协,即不能实时更新榜单。其实现方案是:定时每隔1分钟(可以由产品确定时间间隔)通过SQL(select * from tb_apps order by download_count desc, updated_time desc limit 300)或者其他方式计算热门榜单,然后把TOP300用List结构保存到缓存中。

说明:根据应用商店的用户行为分析,真实用户很少会预览10页以后的数据,即使有这种用户,我们也可以忽略掉。所以只需要将总计10页,即10×30=300个APP信息用List结构保存即可。分页取数据时,通过lrange命令即可轻松实现。

这种方案虽然简单,但是非常有用。即使不能做到实时,但是并没有影响用户体验。在项目初期需要快速发布,是一个比较推荐的做法。

方案2

方案2就是本文重点介绍的利用SortedSet实现多维度排序。关注公众号:【阿飞的博客】,更多原创首发!

介绍方案之前,我们再看一下SortedSet排序因子score,它是一个双精度64位的浮点型数字字符串。+inf和-inf都是有效值,能包括的整数范围是-(2^53) 到 +(2^53),或者说是-9007199254740992 到 9007199254740992。

那么,我们如何实现多维度排序呢?答案是构造一个特殊的score。以本文案例为例,排序影响因子是下载量和更新时间,那么我们可以构造一个这样特殊的浮点类型的score:整数部分就是下载量,小数部分就是最后更新时间戳

talk is cheap,show me the code。假设有5个app的下载量和最后更新时间分别如下(说明:更新时间只精确到秒):

  wechat-下载量:12000000,最后更新时间:1564022201;其score为:12000000.1564022201
    qq-下载量:12000000,最后更新时间:1564022222;其score为:12000000.1564022222
    tiktok-下载量:9808900,最后更新时间:1563552267;其score为:9808900.1563552267
    taobao-下载量:11006600,最后更新时间:1564345601;其score为:11006600.1564345601
    alipay-下载量:11006600,最后更新时间:1564345600;其score为:11006600.1564345600

接下来,我们通过如下命令将这5个APP用SortedSet数据类型保存到Redis中:

  zadd TopApp 12000000.1564022201 wechat 12000000.1564022222 qq 9808900.1563552267 tiktok 11006600.1564345601 taobao 11006600.1564345600 alipay

保存后,我们看一下排序结果是否符合我们的预期:

  127.0.0.1:6379> zrevrange TopApp 0 -1
    1) "qq"
    2) "wechat"
    3) "taobao"
    4) "alipay"
    5) "tiktok"

写在最后

是不是很完美?

还不完美,这种讨巧的方式只能实现二维排序。如果有三维排序,四维排序呢?这里笔者提供一种实现参考,即自定义得分权重计算公式,例如:downloadCount*1000+updatedTime;,这种实现无论排序维度多少都搞得定,需要注意的是,在具体实现时一定注意不要让score溢出:

作者:阿飞的博客

来源:https://www.jianshu.com/p/78194d9c8110


看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「方志朋」,公众号后台回复「666」 免费领取我精心整理的进阶资源教程
  4. JS中文网,Javascriptc中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,是给开发者用的 Hacker News,技术文章由为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。

    本文著作权归作者所有,如若转载,请注明出处

    转载请注明:文章转载自「 Java极客技术学习 」https://www.javajike.com

    标题:SortedSet如何实现多维度排序

    链接:https://www.javajike.com/article/1671.html

« Redis源码分析–RDB实现源码阅读
Redis源码分析–AOF文件全量重写源码阅读»

相关推荐

QR code