redis zset 多值排序
最近面试老被问到ZSet相关的排序题,平时也没相关的经验,一问一个不吱声。抽有点时间,自己尝试去想了一种解决方案。
ZSet相关常用命令
添加成员
ZADD [Key] [Score] [Member] //例 向班级a里面插入小明的80分 ZADD a 80 xiaoming
有序获取
//从低到高获取指定区间的人员 ZRANGE [Key] [Start] [Stop] [WITHSCORES //例 获取班级a里面所有人的分数 ZRANGE a 0 -1 WITHSCORES //例 获取班级a里面分数从低到高10个人的分数 ZRANGE a 0 9 WITHSCORES //从高到低获取指定区间的人员 ZREVRANGE [Key] [Start] [Stop] [WITHSCORES]
下标参数 start 和 stop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。
你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。
TIPS: 如果分数相同的话,Redis会按照Member的词典顺序排序。比如 xiaoming和 xiaoli 都是80分,但是他两中的 l < m ,会导致分数从小到大 xiaoli 排在 xiaoming 前面。
增加分数
ZINCRBY [Key] [Score_Step] [Member] //例 发现班级a里面小明分数统计错误,需要再加10分
ZINCRBY a 10 xiaoming
Redis场景设计
某公司举办了一次小型售卖公司周边礼物的活动,需要你实时统计这场活动商品售卖数量前x的商品。
用zset实现也比较简单,以 活动ID 为Key , 商品ID 为 Member,售卖额为 Score。每次商品售卖量增加时调用 ZINCRBY 原子增加 Score 即可。
ZADD [活动ID] [售卖数量] [商品ID]
ZINCRBY [活动ID] 1 [商品ID]
一般真实场景没这么简单,比如在此基础上产品肯要求售卖数量相同时,再按照商品价格从低到高排序,相同价格的再按照最新售卖时间从小到大排序。
可以尝试将Score分段,比如定制一个标准Score数值模板 10000000000000 (举个例子,结合业务情况自己设置),将蓝色部分当最新售卖时间排序值,绿色部分是价格排序值,红色部分是真实销售量。售卖量增加只需要加红色部分即可
时间区间的排序值可以利用时间戳计算,但是Score精度只有16位,此时可以将活动创建时间当成时间戳起始值、减少时间戳精确度(以小时级)等方式减少位数。
售卖一个商品之后,每次更新前先查一下redis里面的值,计算一下时间差值再 ZINCRBY 增加 Score。
1、先取出商品对应的score
ZSCORE [活动ID] [商品ID]
2、计算时间部分的变更量(假设变更了1小时)
7200 = time.now().Unix()-time.Unix(score%1000000, 0)
3、对score进行变更
ZINCRBY [活动ID] 1000007200 [商品ID]