zset? 有序集合
zset 保留了 set 不能有重復元素的特點
zset 中的每個元素都有一個唯一的浮點類型的分數(score)與之關聯,使得 zset 內部的元素是可以維護有序性的。但是這個有序不是用下標作為排序依據的,而是根據分數(score)
數據結構 | 是否允許重復元素 | 是否有序 | 有序依據 |
list | 是 | 是 | 索引下標 |
set | 否 | 否 | |
zset | 否 | 是 | 分數 |
常見命令
zadd
添加 \ 更新指定的元素以及關聯的分數到 zset 中(分數符合 double 類型,+inf -inf 合法)
zadd key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...]
返回本次添加成功的元素個數? O(log(N))
XX? 僅用于更新已經存在的元素,不會添加新的元素
NX? 僅用于添加新的元素,不會更新已經存在的元素
LT? 新的分數小于原分數就更新,反之不更新
GT? 新的分數大于原分數就更新,反之不更新
CH? zadd 默認返回本次添加的元素個數,指定選項后,將包含本次更新的元素個數
INCR? 類似 zincrby,將元素的分數加上指定的分數。只能指定一個元素和分數
分數相同時,按照元素自身的字典序排列
分數不同時,按照分數排列
zset? 內部是按照升序排列
zrange
返回指定區間內的元素,按照分數升序
zrange key start stop [withscores]
返回區間內的元素列表? O(log(N) + M)? N 集合中元素的個數? ? M? start 到 stop 的元素個數
加上 withscores 將分數也一起返回
redis 內部存儲數據時,是按照二進制的方式來存儲的
redis 服務器不負責“字符編碼”,把二進制轉換成漢字,需要客戶端支持? ? --raw
zcard
獲取一個 zset 的基數(cardinality),即 zset 中的元素個數
zcard key
返回 zset 中的元素個數? O(1)
zcount
返回分數在 [min, max] 的元素個數(min max 默認包含,可通過 ( 排除)
zcount key min max
返回滿足條件的元素列表個數? O(log(N))
zset 內部會記錄每個元素當前的“排行” \ “次序”(下標)
查詢到元素,就直接知道了元素所在的“次序”,直接把 min 和 max 對應的元素的次序減法
min 和 max 可以寫成浮點數的形式(分數本身就是浮點數)
inf 無窮大? ? ? ? ? ? ? ? ? ? ?-inf? 無窮小
zrevrange
返回指定區間里的元素,按照分數降序排列
zrevrange key start stop [withscores]
返回區間內的元素個數? O(log(N) + M)
zrangebyscore
返回分數在 [min, max] 的元素
zrangebyscore key min max [withscores]
返回區間內的元素列表? O(log(N) + M)
zpopmax zpopmin
刪除并返回分數最高的 count 個元素
zpopmax key [count ...]
zpopmin key [count ...]
返回 分數 和 元素列表? O(log(N) *?count)
雖然 Redis 的有序集合記錄了開頭的元素,但是刪除的時候使用的使用的是通用的刪除函數,導致出現了重新查找的過程? ?O(1)? ——>? O(log(N))
如果存在多個元素,分數相同,同為最大值,zpopmax 刪除時只刪除其中一個元素
按照元素的字典序進行排列
bzpopmax bzpopmin
阻塞版本的 zpopmax? zpopmin
bzpopmax key [key ...] timeout
bzpopmin key [key ...] timeout
返回元素列表? O(log(N))
timeout? 超時時間,支持小寫形式
zrank? zrevrank
返回指定元素的排名(下標從 0 開始)
zrank key member? 升序
zrevrank key member? 降序
返回排名? O(log(N))
zcount? 在計算時,先根據分數找到元素,再根據元素獲取排名,把排名一減,得到元素個數
rev >= reverse
zscore
返回指定元素的分數
zscore key member
返回分數? O(1)
zrem
刪除指定的元素
zrem key member [member ...]
返回本次刪除的元素個數? O(log(N) * count)
zremrangebyrank
按照排序,刪除指定范圍內的元素(左閉右閉)升序
zremrangebyrank key start stop
返回本次刪除的元素個數? O(log(N) + M)
zremrangebyscore
按照分數,刪除指定范圍內的元素(左閉右閉)升序
zremrangebyscore key min max? ? ? ?(? 排除邊界值
返回本次刪除的元素個數? O(log(N) + M)
zincrby
為指定的元素的關聯分數添加指定的分數值
zincrby key increment member
返回增加后的元素的分數? O(log(N))
zinter zinterstore
求出給定有序集合中元素的交集,并保存進目標集合中
合并過程中以元素為單位,元素對應的分數按照不同的聚合方式和權重得到新的分數
zinter numkeys key [key ...] [weights weight [weight ...]] [aggreg <sum | min | max >]
zinterstore destination?numkeys key [key ...] [weights weight [weight ...]]
[aggreg <sum | min | max >]
返回目標集合的元素列表
返回目標集合中的元素個數? O(N*K) + O(M*log(M))
N? 最小集合的元素個數? ? ?K? 集合的個數? ? ? M? 目標集合的元素個數
zunion? zunionstore
求出給定有序集合中元素的并集,并保存進目標集合中
zuoion numkeys key [key ...] [weights weight [weight ...]] [aggreg <sum | min | max >]
zunionstore?destination?numkeys key [key ...] [weights weight [weight ...]]
[aggreg <sum | min | max >]
O(N) + O(log(M) * M)
N? 集合的個數? ? ?M? 目標集合的元素個數
內部編碼
1)ziplist(壓縮列表)元素個數較少或者元素的體積較小
2)skiplist(跳表)
跳表是一個“復雜鏈表”,查詢元素 O(N),相比于樹狀結構,更適合按照范圍獲取元素 (B+樹)
應用場景
排行榜系統
例如網站上的熱搜信息,榜單的維度是多方面的,“分數”是實時變化的
只要把相關信息和對應的分數放到 zset 中就會自動排序
隨時可以按照下表進行查詢,隨著分數變化,使用 zincrby 也更方便,還可以自動排序
對于不同維度,可以將不同維度的數值都放到一個有序集合中,通過 zinterstore 或者 zunionstore 把上述集合按照權重進行集合間運算,得到結果集合