最近面試老被問到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]