redis zset 多值排序

FCmmmmmm發表於2024-07-06

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

相關文章