Redis 有序集合

簡介

有序集合是給每一個元素設置一個分數(score)做爲排序的依據這一律唸的集合,其也是不能有重複元素的。有序集合提供了獲取指定分數和元素範圍查詢、計算成員排名等功能。java

數據結構 是否容許重複元素 是否有序 有序實現方式 應用場景
列表 索引 時間軸、消息隊列等
集合 標籤、社交關係等
有序結合 分數 排行榜等

命令

集合內

添加成員

ZADD

自1.2.0可用。python

時間複雜度:O(M*log(N)), N 是有序集的基數, M 爲成功添加的新成員的數量。redis

語法:ZADD key [NX|XX][CH][INCR] score member [score member ...]
說明:

將一個或多個 member 元素及其 score 值加入到有序集 key 當中。shell

若是某個 member 已是有序集的成員,那麼更新這個 memberscore 值,並經過從新插入這個 member 元素,來保證該 member 在正確的位置上。數組

score 值能夠是整數值或雙精度浮點數。ruby

若是 key 不存在,則建立一個空的有序集並執行 ZADD 操做。數據結構

key 存在但不是有序集類型時,返回一個錯誤。函數

在 Redis 2.4 版本之前, ZADD 每次只能添加一個元素。ui

Redis 3.0.2 爲 ZADD 命令添加了 NX XX CH INCR 四個選項:編碼

  • NX member 必須不存在,才能夠設置成功,用於添加。

  • XXmember 必須存在,才能夠設置成功,用於更新。

  • CH :返回這次操做後,有序集合元素和分數發生變化的個數

  • INCR :對 score 作增長,至關於後面介紹的ZINCRBY

返回值:

被成功添加的新成員的數量,不包括那些被更新的、已經存在的成員。

示例:
coderknock> ZADD ztest 100 java 99 python 80 go 120 kotlin
(integer) 4
# 查看有序集合內全部元素而且按分數排序
 coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "100"
7) "kotlin"
8) "120"
# 選項填寫在 key 後面,位置不能錯誤
 coderknock> ZADD ztest 100 java 99 python 80 go 120 kotlin CH
(error) ERR syntax error
 coderknock> ZADD CH ztest 100 java 99 python 80 go 120 kotlin
(error) ERR syntax error
# 下面兩個語句進行了對比,若是不加 CH 顯示的數量不包括更新和已經存在的。
 coderknock>  ZADD ztest CH 100 java 99 python 80 go 121 kotlin
(integer) 1
 coderknock>  ZADD ztest 100 java 99 python 80 go 120 kotlin
(integer) 0

有序集合相比集合提供了排序字段,可是也產生了代價,ZADD 的時間複雜度爲O(log(n)),SADD 的時間複雜度爲 O(1)。

計算成員個數

ZCARD

自1.2.0可用。

時間複雜度:O(1)。

語法:ZCARD key
說明:

返回有序集 key 的基數。

返回值:

key 存在且是有序集類型時,返回有序集的基數。

key 不存在時,返回 0

示例:
coderknock> ZCARD ztest
(integer) 4
 coderknock> ZCARD nonKey
(integer) 0

### 計算某個成員分數

#### ZSCORE

自1.2.0可用。

時間複雜度:O(1)。

語法:ZSCORE key member
說明:

返回有序集 key 中,成員 memberscore 值。

若是 member 元素不是有序集 key 的成員,或 key 不存在,返回 nil

返回值:

member 成員的 score 值,以字符串形式表示。

若是 member 元素不是有序集 key 的成員,或 key 不存在,返回 nil

示例:
coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "100"
7) "kotlin"
8) "120"
 coderknock> ZSCORE ztest java
"100"
# 不存在時返回 nil
 coderknock> ZSCORE ztest ruby
(nil)

### 計算成員的排名

#### ZRANK

自2.0.0可用。

時間複雜度:O(log(N))。

語法:ZRANK key member
說明:

返回有序集 key 中成員 member 的排名。其中有序集成員按 score 值遞增(從小到大)順序排列。

排名以 0 爲底,也就是說, score 值最小的成員排名爲 0

使用 ZREVRANK 命令能夠得到成員按 score 值遞減(從大到小)排列的排名。

返回值:

若是 member 是有序集 key 的成員,返回 member 的排名。

若是 member 不是有序集 key 的成員,返回 nil

示例:
coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "100"
7) "kotlin"
8) "120"
# 沒有 WITHSCORES 選項的話則不顯示分數
 coderknock> ZRANGE ztest 0 -1
1) "go"
2) "python"
3) "java"
4) "kotlin"
 coderknock> ZRANK ztest java
(integer) 2 # 排名從 0 開始
 coderknock> ZRANK ztest ruby
(nil)

#### ZREVRANK

自2.0.0可用。

時間複雜度:O(log(N))。

語法:ZREVRANK key member
說明:

返回member存儲在排序集中的排名key,其中從高到低排列。排名(或索引)爲0,這意味着具備最高分數的成員具備排名0

使用 ZRANK 得到從低到高排列的分數的元素的排名。

返回值:

若是 member存在於排序集中,則 整數回覆 :排名member

若是 member 排序集中key不存在或不存在,則 批量字符串回覆nil

示例:
coderknock> ZREVRANGE ztest 0 -1 WITHSCORES
1) "kotlin"
2) "120"
3) "java"
4) "100"
5) "python"
6) "99"
7) "go"
8) "80"
# 沒有 WITHSCORES 選項的話則不顯示分數
 coderknock>  ZREVRANGE ztest 0 -1
1) "kotlin"
2) "java"
3) "python"
4) "go"
 coderknock> ZREVRANK ztest java
(integer) 1  # 排名從 0 開始

### 刪除成員

#### ZREM

自1.2.0可用。

時間複雜度:O(M*log(N)), N 爲有序集的基數, M 爲被成功移除的成員的數量。

語法:ZREM key member [member ...]
說明:

移除有序集 key 中的一個或多個成員,不存在的成員將被忽略。

key 存在但不是有序集類型時,返回一個錯誤。

在 Redis 2.4 版本之前, ZREM 每次只能刪除一個元素。

返回值:

被成功移除的成員的數量,不包括被忽略的成員。

示例:
coderknock> ZREVRANK ztest java
(integer) 1
 coderknock> ZRANGE ztest 0 -1
1) "go"
2) "python"
3) "java"
4) "kotlin"
 coderknock> ZREM ztest python
(integer) 1
 coderknock> ZRANGE ztest 0 -1
1) "go"
2) "java"
3) "kotlin"
 coderknock> ZREM ztest java ruby python go
(integer) 2

### 增長成員的分數

#### ZINCRBY

自1.2.0可用。

時間複雜度:O(log(N))。

語法:ZINCRBY key increment member
說明:

爲有序集 key 的成員 memberscore 值加上增量 increment

能夠經過傳遞一個負數值 increment ,讓 score 減去相應的值,好比 ZINCRBY key -5 member ,就是讓 memberscore 值減去 5

key 不存在,或 member 不是 key 的成員時, ZINCRBY key increment member 等同於 ZADD key increment member

key 不是有序集類型時,返回一個錯誤。

score 值能夠是整數值或雙精度浮點數。

返回值:

member 成員的新 score 值,以字符串形式表示。

示例:
coderknock> ZSCORE ztest java
"100"
 coderknock> ZINCRBY ztest 2 java
"102"
 coderknock> ZSCORE ztest java
"102"

### 返回指定排名範圍的成員

#### ZRANGE

自1.2.0可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數,而 M 爲結果集的基數。

語法:ZRANGE key start stop [WITHSCORES]
說明:

返回有序集 key 中,指定區間內的成員。

其中成員的位置按 score 值遞增(從小到大)來排序。

具備相同 score 值的成員按字典序( lexicographical order )來排列。

若是你須要成員按 score 值遞減(從大到小)來排列,請使用 ZREVRANGE 命令。

下標參數 startstop 都以 0 爲底,也就是說,以 0 表示有序集第一個成員,以 1 表示有序集第二個成員,以此類推。

你也可使用負數下標,以 -1 表示最後一個成員, -2 表示倒數第二個成員,以此類推。

超出範圍的下標並不會引發錯誤。

好比說,當 start 的值比有序集的最大下標還要大,或是 start > stop 時, ZRANGE 命令只是簡單地返回一個空列表。

另外一方面,假如 stop 參數的值比有序集的最大下標還要大,那麼 Redis 將 stop 看成最大下標來處理。

能夠經過使用 WITHSCORES 選項,來讓成員和它的 score 值一併返回,返回列表以 value1,score1, ..., valueN,scoreN 的格式表示。

客戶端庫可能會返回一些更復雜的數據類型,好比數組、元組等。

返回值:

指定區間內,帶有 score 值(可選)的有序集成員的列表。

示例:
coderknock> ZRANGE ztest 0 -1
1) "go"
2) "python"
3) "java"
4) "kotlin"
 coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "102"
7) "kotlin"
8) "120"
# start > stop 則返回空集合
 coderknock> ZRANGE ztest 3 2 WITHSCORES
(empty list or set)
 coderknock> ZRANGE ztest 2 5 WITHSCORES
1) "java"
2) "102"
3) "kotlin"
4) "120"
# stop > 總長度
 coderknock> ZRANGE ztest 2 1000 WITHSCORES
1) "java"
2) "102"
3) "kotlin"
4) "120"

#### ZRANGE

自1.2.0可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數,而 M 爲結果集的基數。

語法:ZRANGE key start stop [WITHSCORES]
說明:

返回有序集 key 中,指定區間內的成員。

其中成員的位置按 score 值遞減(從大到小)來排列。

具備相同 score 值的成員按字典序的逆序( reverse lexicographical order )排列。

除了成員按 score 值遞減的次序排列這一點外, ZREVRANGE 命令的其餘方面和 ZRANGE 命令同樣。

返回值:

指定區間內,帶有 score 值(可選)的有序集成員的列表。

示例:
coderknock> ZREVRANGE ztest 0 -1
1) "kotlin"
2) "java"
3) "python"
4) "go"
 coderknock> ZREVRANGE ztest 0 -1 WITHSCORES
1) "kotlin"
2) "120"
3) "java"
4) "102"
5) "python"
6) "99"
7) "go"
8) "80"

### 返回指定分數範圍的成員

#### ZRANGEBYSCORE

自1.0.5可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數, M 爲被結果集的基數。

語法:ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count]
說明:

返回有序集 key 中,全部 score 值介於 minmax 之間(包括等於 minmax )的成員。有序集成員按 score 值遞增(從小到大)次序排列。

具備相同 score 值的成員按字典序( lexicographical order )來排列(該屬性是有序集提供的,不須要額外的計算)。

可選的 LIMIT 參數指定返回結果的數量及區間(就像SQL中的 SELECT LIMIT offset, count ),注意當 offset 很大時,定位 offset 的操做可能須要遍歷整個有序集,此過程最壞複雜度爲 O(N) 時間。

可選的 WITHSCORES 參數決定結果集是單單返回有序集的成員,仍是將有序集成員及其 score 值一塊兒返回。

該選項自 Redis 2.0 版本起可用。

區間及無限

minmax 能夠是 -inf+inf ,這樣一來,你就能夠在不知道有序集的最低和最高 score 值的狀況下,使用 ZRANGEBYSCORE 這類命令。

默認狀況下,區間的取值使用 閉區間 (小於等於或大於等於),你也能夠經過給參數前增長 ( 符號來使用可選的 開區間 (小於或大於)。

舉個例子:

ZRANGEBYSCORE zset (1 5

返回全部符合條件 1 < score <= 5 的成員,而

ZRANGEBYSCORE zset (5 (10

則返回全部符合條件 5 < score < 10 的成員。

返回值:

指定區間內,帶有 score 值(可選)的有序集成員的列表。

示例:
coderknock> ZRANGEBYSCORE ztest 80 100 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
# 開區間用法
 coderknock> ZRANGEBYSCORE ztest (80 100 WITHSCORES
1) "python"
2) "99"
# 查詢全部
 coderknock> ZRANGEBYSCORE ztest -inf +inf WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "102"
7) "kotlin"
8) "120"
 coderknock> ZRANGEBYSCORE ztest -inf +inf WITHSCORES LIMIT 1 2
1) "python"
2) "99"
3) "java"
4) "102"

#### ZREVRANGEBYSCORE

自1.0.5可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數, M 爲被結果集的基數。

語法:ZREVRANGEBYSCORE key max min [WITHSCORES][LIMIT offset count]
說明:

返回有序集 key 中, score 值介於 maxmin 之間(默認包括等於 maxmin )的全部的成員。有序集成員按 score 值遞減(從大到小)的次序排列。

具備相同 score 值的成員按字典序的逆序( reverse lexicographical order )排列。

除了成員按 score 值遞減的次序排列這一點外, ZREVRANGEBYSCORE 命令的其餘方面和 ZRANGEBYSCORE 命令同樣。

返回值:

指定區間內,帶有 score 值(可選)的有序集成員的列表。

示例:
# max min 參數位置也有區別
 coderknock> ZREVRANGEBYSCORE ztest -inf +inf WITHSCORES LIMIT 1 2
(empty list or set)
 coderknock>  ZREVRANGEBYSCORE ztest +inf -inf WITHSCORES LIMIT 1 2
1) "java"
2) "102"
3) "python"
4) "99"

### 返回指定分數範圍成員個數

#### ZCOUNT

自2.0.0可用。

時間複雜度:O(log(N)), N 爲有序集的基數。

語法:ZCOUNT key min max
說明:

返回有序集 key 中, score 值在 minmax 之間(默認包括 score 值等於 minmax )的成員的數量。

關於參數 minmax 的詳細使用方法,請參考 ZRANGEBYSCORE 命令。

返回值:

score 值在 minmax 之間的成員的數量。

示例:
coderknock> ZCOUNT ztest -inf +inf
(integer) 4
 coderknock> ZCOUNT ztest 80 100
(integer) 2

### 刪除指定排名內的升序元素

#### ZREMRANGEBYRANK

自2.0.0可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數,而 M 爲被移除成員的數量。

語法:ZREMRANGEBYRANK key start stop
說明:

移除有序集 key 中,指定排名(rank)區間內的全部成員。

區間分別如下標參數 startstop 指出,包含 startstop 在內。

下標參數 startstop 都以 0 爲底,也就是說,以 0 表示有序集第一個成員,以 1 表示有序集第二個成員,以此類推。

你也可使用負數下標,以 -1 表示最後一個成員, -2 表示倒數第二個成員,以此類推。

返回值:

被移除成員的數量。

示例:
# 查詢全部
 coderknock> ZRANGEBYSCORE ztest -inf +inf WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "102"
7) "kotlin"
8) "120"
 coderknock> ZREMRANGEBYRANK ztest 1 3
(integer) 3
 coderknock> ZRANGE ztest 0 -1
1) "go"

### 刪除指定分數內的成員

#### ZREMRANGEBYSCORE

自1.2.0可用。

時間複雜度:O(log(N)+M), N 爲有序集的基數,而 M 爲被移除成員的數量。

語法:ZREMRANGEBYSCORE key min max
說明:

移除有序集 key 中,全部 score 值介於 minmax 之間(包括等於 minmax )的成員。

自版本2.1.6開始, score 值等於 minmax 的成員也能夠不包括在內,詳情請參見 ZRANGEBYSCORE 命令。

返回值:

被移除成員的數量。

示例:
coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "100"
7) "kotlin"
8) "120"
 coderknock> ZREMRANGEBYSCORE ztest 80 100
(integer) 3
 coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "kotlin"
2) "120"

## 集合間操做

### 並集

#### ZUNIONSTORE

自2.0.0可用。

時間複雜度:O(N)+O(M log(M)), N 爲給定有序集基數的總和, M 爲結果集的基數。

語法:ZUNIONSTORE destination numkeys key [key ...][WEIGHTS weight [weight ...]][AGGREGATE SUM|MIN|MAX]
說明:

計算給定的一個或多個有序集的並集,其中給定 key 的數量必須以 numkeys 參數指定,並將該並集(結果集)儲存到 destination

默認狀況下,結果集中某個成員的 score 值是全部給定集下該成員 score 值之

WEIGHTS

使用 WEIGHTS 選項,你能夠爲 每一個 給定有序集 分別 指定一個乘法因子(multiplication factor),每一個給定有序集的全部成員的 score 值在傳遞給聚合函數(aggregation function)以前都要先乘以該有序集的因子。

若是沒有指定 WEIGHTS 選項,乘法因子默認設置爲 1

AGGREGATE

使用 AGGREGATE 選項,你能夠指定並集的結果集的聚合方式。

默認使用的參數 SUM ,能夠將全部集合中某個成員的 score 值之 做爲結果集中該成員的 score 值;使用參數 MIN ,能夠將全部集合中某個成員的 最小 score 值做爲結果集中該成員的 score 值;而參數 MAX 則是將全部集合中某個成員的 最大 score 值做爲結果集中該成員的 score 值。

返回值:

保存到 destination 的結果集的基數。

示例:
coderknock> ZRANGE setTest 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
 coderknock> ZRANGE setTest2 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "4"
 coderknock> ZUNIONSTORE outTest 2 setTest setTest2 WEIGHTS 2 3
(integer) 4
 coderknock> ZRANGE outTest 0 -1 WITHSCORES
1) "one"
2) "5"
3) "two"
4) "10"
5) "four"
6) "12"
7) "three"
8) "15"

### 交集

#### ZINTERSTORE

自1.0.0可用。

時間複雜度:O(1)。

語法:ZINTERSTOREdestination numkeys key [key ...][WEIGHTS weight [weight ...]][AGGREGATE SUM|MIN|MAX]**
說明:

計算給定的一個或多個有序集的交集,其中給定 key 的數量必須以 numkeys 參數指定,並將該交集(結果集)儲存到 destination

默認狀況下,結果集中某個成員的 score 值是全部給定集下該成員 score 值之和.

關於 `WEIGHTS` 和 `AGGREGATE` 選項的描述,參見  `ZUNIONSTORE`  命令。
返回值:

保存到 destination 的結果集的基數。

示例:
coderknock> ZRANGE setTest 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
 coderknock> ZRANGE setTest2 0 -1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "four"
8) "4"
 coderknock> ZINTERSTORE zinterstoreTest 2 setTest setTest2
(integer) 3
 coderknock> ZRANGE zinterstoreTest 0 -1 WITHSCORES
1) "one"
2) "2"
3) "two"
4) "4"
5) "three"
6) "6"

內部編碼

有序集合類型的內部編碼有兩種:

  • ziplist(壓縮列表):當有序集合的元素個數小於 zset-max-ziplistentries 配置(默認128個),同時每一個元素的值都小於 zset-max-ziplist-value 配置(默認64字節)時,Redis會用 ziplist 來做爲有序集合的內部實現,ziplist 能夠有效減小內存的使用。

  • skiplist(跳躍表):當 ziplist 條件不知足時,有序集合會使用 skiplist 做爲內部實現,由於此時ziplist的讀寫效率會降低。

  1. 當元素個數較少且每一個元素較小時,內部編碼爲skiplist:

coderknock> ZRANGE zinterstoreTest 0 -1 WITHSCORES
1) "one"
2) "2"
3) "two"
4) "4"
5) "three"
6) "6"
 coderknock> OBJECT ENCODING zinterstoreTest
"ziplist"
  1. 當元素個數超過128個,內部編碼變爲ziplist:

import redis

r = redis.StrictRedis(host='127.0.0.1', password='admin123', port=6379, db=0)
num = 128
key = "ZSETTest" + str(num)
r.delete(key)
for i in range(num):
    r.zadd(key, i,i)

# 可使用這個命令查詢內部編碼
print(key)
print(r.zcard(key))
print(r.object("ENCODING", key))

當 num = 128 時:

ZSETTest128
128
b'ziplist'

當 num = 129 時:

ZSETTest129
129
b'skiplist'
  1. 當某個元素大於64字節時,內部編碼也會變爲 skiplist :

coderknock> ZADD lg64 20 aaaassssddddffffgggghhhhkj=jjjkkkklllllsdfasdlkfcsdkcaneyuirhworitsuhdiouoooooofovutivhwoeirrthsoiuyqrbwiveyrvisuyrsui
(integer) 1
 coderknock> OBJECT ENCODING lg64
"skiplist"

使用場景

  1. 點贊

  2. 積分系統

  3. 分頁

  4. 排序

相關文章
相關標籤/搜索