SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC | DESC] [ALPHA] [STORE destination]
返回或儲存給定列表、集合、有序集合 key 中經過排序的元素。
排序預設以數字作為對象,值被解釋為雙精確度浮點數,然後進行比較。
一、一般sort用法
最簡單的 SORT 使用方法是 SORT key 和 SORT key DESC :
SORT key 返回索引值從小到大排序的結果。
SORT key DESC 返回索引值從大到小排序的結果。
假設 today_cost 列表儲存了今日的開銷金額, 那麼可以用 SORT 命令對它進行排序:
# 開銷金額列表redis> LPUSH today_cost 30 1.5 10 8(integer) 4# 排序redis> SORT today_cost1) "1.5"2) "8"3) "10"4) "30"# 逆序排序redis 127.0.0.1:6379> SORT today_cost DESC1) "30"2) "10"3) "8"4) "1.5"
二、使用 ALPHA 修飾符對字串進行排序
因為 SORT 命令預設排序對象為數字, 當需要對字串進行排序時, 需要顯式地在 SORT 命令之後添加 ALPHA 修飾符:
# 網址redis> LPUSH website "www.reddit.com"(integer) 1redis> LPUSH website "www.slashdot.com"(integer) 2redis> LPUSH website "www.infoq.com"(integer) 3# 預設(按數字)排序redis> SORT website1) "www.infoq.com"2) "www.slashdot.com"3) "www.reddit.com"# 按字元排序redis> SORT website ALPHA1) "www.infoq.com"2) "www.reddit.com"3) "www.slashdot.com"
如果系統正確地設定了 LC_COLLATE 環境變數的話,Redis能識別 UTF-8 編碼。 三、使用 LIMIT 修飾符限制返回結果
排序之後返回元素的數量可以通過 LIMIT 修飾符進行限制, 修飾符接受 offset 和 count 兩個參數:
offset 指定要跳過的元素數量。
count 指定跳過 offset 個指定的元素之後,要返回多少個對象。
以下例子返回排序結果的前 5 個對象( offset 為 0 表示沒有元素被跳過)。
# 添加測試資料,列表值為 1 指 10redis 127.0.0.1:6379> RPUSH rank 1 3 5 7 9(integer) 5redis 127.0.0.1:6379> RPUSH rank 2 4 6 8 10(integer) 10# 返回列表中最小的 5 個值redis 127.0.0.1:6379> SORT rank LIMIT 0 51) "1"2) "2"3) "3"4) "4"5) "5"
可以組合使用多個修飾符。以下例子返回從大到小排序的前 5 個對象。
redis 127.0.0.1:6379> SORT rank LIMIT 0 5 DESC1) "10"2) "9"3) "8"4) "7"5) "6"
四、使用外部 key 進行排序
可以使用外部 key 的資料作為權重,代替預設的直接對比索引值的方式來進行排序。
假設現在有使用者資料如下:
uid user_name_{uid} user_level_{uid}
1 admin 9999
2 jack 10
3 peter 25
4 mary 70
以下代碼將資料輸入到 Redis 中:
# adminredis 127.0.0.1:6379> LPUSH uid 1(integer) 1redis 127.0.0.1:6379> SET user_name_1 adminOKredis 127.0.0.1:6379> SET user_level_1 9999OK# jackredis 127.0.0.1:6379> LPUSH uid 2(integer) 2redis 127.0.0.1:6379> SET user_name_2 jackOKredis 127.0.0.1:6379> SET user_level_2 10OK# peterredis 127.0.0.1:6379> LPUSH uid 3(integer) 3redis 127.0.0.1:6379> SET user_name_3 peterOKredis 127.0.0.1:6379> SET user_level_3 25OK# maryredis 127.0.0.1:6379> LPUSH uid 4(integer) 4redis 127.0.0.1:6379> SET user_name_4 maryOKredis 127.0.0.1:6379> SET user_level_4 70OK
BY 選項
預設情況下, SORT uid 直接按 uid 中的值排序:
redis 127.0.0.1:6379> SORT uid1) "1" # admin2) "2" # jack3) "3" # peter4) "4" # mary
通過使用 BY 選項,可以讓 uid 按其他鍵的元素來排序。
比如說, 以下代碼讓 uid 鍵按照 user_level_{uid} 的大小來排序:
redis 127.0.0.1:6379> SORT uid BY user_level_*1) "2" # jack , level = 102) "3" # peter, level = 253) "4" # mary, level = 704) "1" # admin, level = 9999
user_level_* 是一個預留位置, 它先取出 uid 中的值, 然後再用這個值來尋找相應的鍵。
比如在對 uid 列表進行排序時, 程式就會先取出 uid 的值 1 、 2 、 3 、 4 , 然後使用 user_level_1 、 user_level_2 、 user_level_3 和 user_level_4 的值作為排序 uid 的權重。
GET 選項
使用 GET 選項, 可以根據排序的結果來取出相應的索引值。
比如說, 以下代碼先排序 uid , 再取出鍵 user_name_{uid} 的值:
redis 127.0.0.1:6379> SORT uid GET user_name_*1) "admin"2) "jack"3) "peter"4) "mary"
組合使用 BY 和 GET
通過組合使用 BY 和 GET , 可以讓排序結果以更直觀的方式顯示出來。
比如說, 以下代碼先按 user_level_{uid} 來排序 uid 列表, 再取出相應的 user_name_{uid} 的值:
redis 127.0.0.1:6379> SORT uid BY user_level_* GET user_name_*1) "jack" # level = 102) "peter" # level = 253) "mary" # level = 704) "admin" # level = 9999
現在的排序結果要比只使用 SORT uid BY user_level_* 要直觀得多。
擷取多個外部鍵
可以同時使用多個 GET 選項, 擷取多個外部鍵的值。
以下代碼就按 uid 分別擷取 user_level_{uid} 和 user_name_{uid} :
redis 127.0.0.1:6379> SORT uid GET user_level_* GET user_name_*1) "9999" # level2) "admin" # name3) "10"4) "jack"5) "25"6) "peter"7) "70"8) "mary"
GET 有一個額外的參數規則,那就是 —— 可以用 # 擷取被排序鍵的值。
以下代碼就將 uid 的值、及其相應的 user_level_* 和 user_name_* 都返回為結果:
redis 127.0.0.1:6379> SORT uid GET # GET user_level_* GET user_name_*1) "1" # uid2) "9999" # level3) "admin" # name4) "2"5) "10"6) "jack"7) "3"8) "25"9) "peter"10) "4"11) "70"12) "mary"
擷取外部鍵,但不進行排序
通過將一個不存在的鍵作為參數傳給 BY 選項, 可以讓 SORT 跳過排序操作, 直接返回結果:
redis 127.0.0.1:6379> SORT uid BY not-exists-key1) "4"2) "3"3) "2"4) "1"
這種用法在單獨使用時,沒什麼實際用處。
不過,通過將這種用法和 GET 選項配合, 就可以在不排序的情況下, 擷取多個外部鍵, 相當於執行一個整合的擷取操作(類似於 SQL 資料庫的 join 關鍵字)。
以下代碼示範了,如何在不引起排序的情況下,使用 SORT 、 BY 和 GET 擷取多個外部鍵:
redis 127.0.0.1:6379> SORT uid BY not-exists-key GET # GET user_level_* GET user_name_*1) "4" # id2) "70" # level3) "mary" # name4) "3"5) "25"6) "peter"7) "2"8) "10"9) "jack"10) "1"11) "9999"12) "admin"
將雜湊表作為 GET 或 BY 的參數
除了可以將字串鍵之外, 雜湊表也可以作為 GET 或 BY 選項的參數來使用。
比如說,對於前面給出的使用者資訊表:
uid user_name_{uid} user_level_{uid}1 admin 99992 jack 103 peter 254 mary 70
我們可以不將使用者的名字和層級儲存在 user_name_{uid} 和 user_level_{uid} 兩個字串鍵中, 而是用一個帶有 name 域和 level 域的雜湊表 user_info_{uid} 來儲存使用者的名字和層級資訊:
redis 127.0.0.1:6379> HMSET user_info_1 name admin level 9999OKredis 127.0.0.1:6379> HMSET user_info_2 name jack level 10OKredis 127.0.0.1:6379> HMSET user_info_3 name peter level 25OKredis 127.0.0.1:6379> HMSET user_info_4 name mary level 70OK
之後, BY 和 GET 選項都可以用 key->field 的格式來擷取雜湊表中的域的值, 其中 key 表示雜湊表鍵, 而 field 則表示雜湊表的域:
redis 127.0.0.1:6379> SORT uid BY user_info_*->level1) "2"2) "3"3) "4"4) "1"redis 127.0.0.1:6379> SORT uid BY user_info_*->level GET user_info_*->name1) "jack"2) "peter"3) "mary"4) "admin"
五、儲存排序結果
預設情況下, SORT 操作只是簡單地返回排序結果,並不進行任何儲存操作。
通過給 STORE 選項指定一個 key 參數,可以將排序結果儲存到給定的鍵上。
如果被指定的 key 已存在,那麼原有的值將被排序結果覆蓋。
# 測試資料redis 127.0.0.1:6379> RPUSH numbers 1 3 5 7 9(integer) 5redis 127.0.0.1:6379> RPUSH numbers 2 4 6 8 10(integer) 10redis 127.0.0.1:6379> LRANGE numbers 0 -11) "1"2) "3"3) "5"4) "7"5) "9"6) "2"7) "4"8) "6"9) "8"10) "10"redis 127.0.0.1:6379> SORT numbers STORE sorted-numbers(integer) 10
# 排序後的結果redis 127.0.0.1:6379> LRANGE sorted-numbers 0 -11) "1"2) "2"3) "3"4) "4"5) "5"6) "6"7) "7"8) "8"9) "9"10) "10"
可以通過將 SORT 命令的執行結果儲存,並用 EXPIRE 為結果設定存留時間,以此來產生一個 SORT 操作的結果緩衝。
這樣就可以避免對 SORT 操作的頻繁調用:只有當結果集到期時,才需要再調用一次 SORT 操作。
另外,為了正確實現這一用法,你可能需要加鎖以避免多個用戶端同時進行緩衝重建(也就是多個用戶端,同一時間進行 SORT 操作,並儲存為結果集),具體參見 SETNX 命令。
可用版本:
>= 1.0.0
時間複雜度:
O(N+M*log(M)), N 為要排序的列表或集合內的元素數量, M 為要返回的元素數量。
如果只是使用 SORT 命令的 GET 選項擷取資料而沒有進行排序,時間複雜度 O(N)。
傳回值:
沒有使用 STORE 參數,返回列表形式的排序結果。
使用 STORE 參數,返回排序結果的元素數量。