一、簡介

有序集合保留了集合不能有重複成員的特點,但與集合不同的是,有序集合中的每個元素都有⼀個唯⼀的浮點類型的分數(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 的操作效率會下降。

四、使用場景

有序集合⽐較典型的使⽤場景就是排⾏榜系統。例如常⻅的⽹站上的熱榜信息,榜單的維度可能是多⽅⾯的:按照時間、按照閲讀量、按照點贊量。