一、簡介
有序集合保留了集合不能有重複成員的特點,但與集合不同的是,有序集合中的每個元素都有⼀個唯⼀的浮點類型的分數(score)與之關聯,這使得有序集合中的元素是可以維護有序性的,但這個有序不是⽤下標作為排序依據⽽是⽤這個 分數。
有序集合提供了獲取指定分數和元素範圍查找、計算成員排名等功能,有序集合中的元素是不能重複的,但分數允許重複。類⽐於⼀次考試之後,每個⼈⼀定有⼀個唯⼀的分數,但分數允許相同。
列表、集合、有序集合三者的異同點:
|
數據結構
|
是否允許重複元素
|
是否有序
|
有序依據
|
應⽤場景
|
|
列表
|
是
|
是
|
索引下標
|
時間軸、消息隊列等
|
|
集合
|
否
|
否
|
|
標籤、社交等
|
|
有序集合
|
否
|
是
|
分數
|
排⾏榜系統、社交等
|
二、相關命令
2.1 zadd
zadd添加或者更新指定的元素以及關聯的分數到 zset 中,分數應該符合 double 類型,+inf/-inf 作為正負極限也是合法的。
語法: zadd key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]
- XX:僅僅⽤於更新已經存在的元素,不會添加新元素。
- NX:僅⽤於添加新元素,不會更新已經存在的元素。
- LT:如果更新的分數比已經存在的分數小才更新已經存在的元素,不會影響添加新元素。
- GT:如果更新的分數比已經存在的分數大才更新已經存在的元素,不會影響添加新元素。
- CH:默認情況下,zadd 返回的是本次添加的元素個數,但指定這個選項之後,就會還包含本次更新的元素的個數。
- INCR:此時命令類似 zincrby 的效果,將元素的分數加上指定的分數。此時只能指定⼀個元素和分數。
命令有效版本:1.2.0 之後
時間複雜度:O(logN),N是有序集合中已經存在的元素個數 返回值:本次添加成功的元素個數。
2.2 zcard 和 zcount
zcard獲取⼀個 zset 的基數(cardinality),即 zset 中的元素個數。
語法: zcard key
命令有效版本:1.2.0 之後
時間複雜度:O(1) 返回值:zset 內的元素個數。
zcount返回分數在 min 和 max 之間的元素個數,默認情況下,min 和 max 都是包含的,可以通過 ( 排除。min 和 max支持浮點數,inf : 代表無窮大,-inf:代表負無窮大。
語法: zcount key min max
命令有效版本:2.0.0 之後
時間複雜度:O(logN),N是有序集合中已經存在的元素個數 返回值:滿⾜條件的元素列表個數。
2.3 zrange 和 zrevrange 和 zrangebyscore
zrange返回指定區間⾥的元素,分數按照升序。帶上 WITHSCORES 可以把分數也返回。
語法: zrange key start stop [WITHSCORES] 此處的 [start, stop] 為下標構成的區間. 從 0 開始, ⽀持負數.
命令有效版本:1.2.0之後
時間複雜度:O(log(N)+M),N是有序集合中已經存在的元素個數,M是查找到的元素個數 返回值:區間內的元素列表。
zrevrange返回指定區間⾥的元素,分數按照降序。帶上 WITHSCORES 可以把分數也返回。
備註:這個命令可能在 6.2.0 之後廢棄,並且功能合併到
zrange中。
語法: zrevrange key start stop [WITHSCORES]
命令有效版本:1.2.0之後
時間複雜度:O(log(N)+M),N是有序集合中已經存在的元素個數,M是查找到的元素個數 返回值:區間內的元素列表。
zrangebyscore返回分數在 min 和 max 之間的元素,默認情況下,min 和 max 都是包含的,可以通過 ( 排除。
備註:這個命令可能在 6.2.0 之後廢棄,並且功能合併到
zrange中。
語法: zrangebyscore key min max [WITHSCORES]
命令有效版本:1.0.5 之後
時間複雜度:O(log(N)+M),N是有序集合中已經存在的元素個數,M是查找到的元素個數 返回值:區間內的元素列表。
2.4 zpopmax 和 bzpopmax
zpopmax刪除並返回分數最⾼的 count 個元素。
語法: zpopmax key [count]
命令有效版本:5.0.0 之後
時間複雜度:O(log(N) * M),N是有序集合中已經存在的元素個數,M是刪除的元素個數 返回值:分數和元素列表。
bzpopmax 命令zpopmax的阻塞版本,一次只能刪一個元素,可以設置最大阻塞時間timeout單位秒。
語法: bzpopmax key [key ...] timeout
命令有效版本:5.0.0 之後
時間複雜度:O(log(N)),N是有序集合中已經存在的元素個數 返回值:元素列表。
2.5 zpopmin 和 bzpopmin
zpopmin刪除並返回分數最低的 count 個元素。
語法: zpopmin key [count]
命令有效版本:5.0.0之後
時間複雜度:O(log(N) * M),N是有序集合中已經存在的元素個數,M是刪除的元素個數 返回值:分數和元素列表。
bzpopmin 命令 zpopmin的阻塞版本,一次只能刪一個元素,可以設置最大阻塞時間timeout單位秒。 bzpopmin key [key ...] timeout
命令有效版本:5.0.0 之後
時間複雜度:O(log(N)),N是有序集合中已經存在的元素個數 返回值:元素列表
2.6 zrank 和 zrevrank 和 zscore
zrank返回指定元素的排名,升序。
語法: zrank key membe
命令有效版本:2.0.0 之後
時間複雜度:O(log(N)),N是有序集合中已經存在的元素個數 返回值:排名。
zrevrank返回指定元素的排名,降序。
語法: zrevrank key member
命令有效版本:2.0.0之後
時間複雜度:O(log(N)),N是有序集合中已經存在的元素個數 返回值:排名。
zscore返回指定元素的分數。
語法: zscore key member
命令有效版本:1.2.0之後
時間複雜度:O(1) 返回值:分數。
2.7 zrem 和 zremrangebyrank 和 zremrangebyscore
zrem刪除指定的元素。
語法: zzrem key member [member ...]
命令有效版本:1.2.0之後
時間複雜度:O(M*log(N)),N是有序集合中已經存在的元素個數 返回值:本次操作刪除的元素個數。
zremrangebyrank按照下標排序,升序刪除指定範圍的元素,左閉右閉。
語法: zremrangebyrank key start stop
命令有效版本:2.0.0之後
時間複雜度:O(log(N)+M),N是有序集合中已經存在的元素個數,M是刪除的元素個數 返回值:本次操作刪除的元素個數。
zremrangebyscore按照分數排序,升序刪除指定範圍的元素,左閉右閉。
語法: zremrangebyscore key start stop
命令有效版本:2.0.0之後
時間複雜度:O(log(N)+M),N是有序集合中已經存在的元素個數,M是刪除的元素個數 返回值:本次操作刪除的元素個數。
2.8 zincrby
zincrby為指定的元素的關聯分數添加指定的分數值。
語法: zincrby key increment member
命令有效版本:1.2.0之後
時間複雜度:O(log(N)),N是有序集合中已經存在的元素個數 返回值:增加後元素的分數。
2.9 zinterstore 和 zunionstore
zinterstore 求出給定有序集合中元素的交集並保存進⽬標有序集合中,在合併過程中以元素為單位進⾏合併,元素對應的分數按照不同的聚合⽅式和權重得到新的分數。
求交集
語法: zinterstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [aggregate <SUM | MIN | MAX>]
- destination : ⽬標有序集合
- numkeys : 給定有序集合的個數,為了區分key和後面的可選項
- weight : 權重,會乘上前面對應的key裏元素的score
- aggregate : 求和(默認),取最小值,取最大值
命令有效版本:2.0.0之後
時間複雜度:O(NK)+O(Mlog(M)) N 是輸⼊的有序集合中, 最⼩的有序集合的元素個數; K 是輸⼊了⼏個有序集合; M 是最終結果的有序集合的元素個數.
返回值:⽬標集合中的元素個數
zunionstore求出給定有序集合中元素的並集並保存進⽬標有序集合中,在合併過程中以元素為單位進⾏合併,元素對應的分數按照不同的聚合⽅式和權重得到新的分數。
求並集
語法 zunionstore destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
命令有效版本:2.0.0之後
時間複雜度:O(N)+O(M*log(M)) N 是輸⼊的有序集合總的元素個數; M 是最終結果的有序集合的元素個數.
返回值:⽬標集合中的元素個數
2.10 命令小結
|
命令
|
執行效果
|
時間複雜度
|
|
zadd key score member [score member ...]
|
添加或者更新指定的元素以及關聯的分數到 zset 中
|
O(k * log(n)),k 是添加成員的個數,n 是當前有序集合的元素個數
|
|
zcard key
|
獲取⼀個 zset 的基數(cardinality),即 zset 中的元素個數。
|
O(1)
|
|
zscore key member
|
返回指定元素的分數
|
O(1)
|
|
zrank key member
|
返回指定元素的排名
|
O(log(n)),n 是當前有序集合的元素個數
|
|
zrevrank key member
|
返回指定元素的排名,降序
|
O(log(n)),n 是當前有序集合的元素個數
|
|
zcount
|
返回分數在 min 和 max 之間的元素個數
|
O(log(n)),n 是當前有序集合的元素個數
|
|
zincrby key increment member
|
為指定的元素的關聯分數添加指定的分數值
|
O(log(n)),n 是當前有序集合的元素個數
|
|
zrange key start end [withscores]
|
返回指定區間⾥的元素,分數按照升序
|
O(log(N)),N是有序集合中已經存在的元素個數
|
|
zrevrange key start end [withscores]
|
返回指定區間⾥的元素,分數按照降序
|
O(k + log(n)),k 是獲取成員的個數,n 是當前有序集合的元素個數
|
|
zrangebyscore key min max[withscores]
|
返回分數在 min 和 max 之間的元素,升序
|
O(k + log(n)),k 是獲取成員的個數,n 是當前有序集合的元素個數 zcount O(log(n)),n 是當前有序集合的元素個數
|
|
zrevrangebyscore key max min [withscores]
|
返回分數在 min 和 max 之間的元素,降序
|
O(k + log(n)),k 是獲取成員的個數,n 是當前有序集合的元素個數
|
|
zrem key member [member ...]
|
刪除指定的元素
|
O(k * log(n)),k 是刪除成員的個數,n 是當前有序集合的元素個數
|
|
zremrangebyrank key start end
|
按照下標排序,升序刪除指定範圍的元素,左閉右閉
|
O(k + log(n)),k 是獲取成員的個數,n 是當前有序集合的元素個數
|
|
zremrangebyscore key min max
|
按照分數排序,降序刪除指定範圍的元素,左閉右閉
|
O(k + log(n)),k 是獲取成員的個數,n 是當前有序集合的元素個數
|
|
zinterstore destination numkeys key [key ...]
|
求出給定有序集合中元素的交集並保存進⽬標有序集合中
|
O(n * k) + O(m * log(m)),n 是輸⼊的集合最⼩的元素個數,k 是集合個數, m 是⽬標集合元素個數
|
|
zunionstore destination numkeys key [ key ...]
|
求出給定有序集合中元素的並集並保存進⽬標有序集合中
|
O(n) + O(m * log(m)),n 是輸⼊集合總元素個數,m 是⽬標集合元素個數
|
三、內部編碼
有序集合類型的內部編碼有兩種:
- ziplist(壓縮列表):當有序集合的元素個數⼩於 zset-max-ziplist-entries 配置(默認 128 個),同時每個元素的值都⼩於 zset-max-ziplist-value 配置(默認 64 字節)時,Redis 會⽤ ziplist 來作為有序集合的內部實現,ziplist 可以有效減少內存的使⽤。
- skiplist(跳錶):當 ziplist 條件不滿⾜時,有序集合會使⽤ skiplist 作為內部實現,因為此時 ziplist 的操作效率會下降。
四、使用場景
有序集合⽐較典型的使⽤場景就是排⾏榜系統。例如常⻅的⽹站上的熱榜信息,榜單的維度可能是多⽅⾯的:按照時間、按照閲讀量、按照點贊量。