- 如何在ubuntu18.04上安裝和保護redis
- 如何連接到Redis資料庫
- 如何管理Redis資料庫和Keys
- 如何在Redis中管理副本和客戶端
- 如何在Redis中管理字串
- 如何在Redis中管理list
- 如何在Redis中管理Hashes
- 如何在Redis中管理Sets
- 如何在Redis中管理Sorted Sets
- 如何在Redis中運行事務
- 如何使Redis中的Key失效
- 如何解決Redis中的問題
- 如何從命令列更改Redis的配置
- Redis資料型別簡介
Redis資料型別簡介
Redis不是_簡單的_鍵值存盤,它實際上是一個_資料結構服務器_,支持不同型別的值,這意味著在傳統鍵值存盤中,您將字串鍵與字串值相關聯,而在Redis中,該值不僅限于簡單的字串,還可以容納更復雜的資料結構,以下是Redis支持的所有資料結構的串列,本教程將分別進行介紹:
- 二進制安全字串,
- 串列:根據插入順序排序的字串元素的集合,它們基本上是_鏈表_,
- 集:唯一,未排序的字串元素的集合,
- 類似于Sets的排序集合,但每個字串元素都與一個稱為_score_的浮點值相關聯,元素總是按它們的分數排序,因此與Sets不同,可以檢索一系列元素(例如,您可能會問:給我前10名或后10名),
- 哈希,是由與值關聯的欄位組成的映射,欄位和值都是字串,這與Ruby或Python哈希非常相似,
- 位陣列(或簡稱為位圖):可以使用特殊命令像位陣列一樣處理字串值:您可以設定和清除單個位,計數所有設定為1的位,找到第一個設定或未設定的位,等等,
- HyperLogLogs:這是一個概率資料結構,用于估計集合的基數,別害怕,它比看起來更簡單...請參閱本教程的HyperLogLog部分,
- 流:提供抽象日志資料型別的類地圖項的僅追加集合,在“ Redis流簡介”中對它們進行了深入 介紹,
從命令參考中掌握這些資料型別的作業方式以及使用什么來解決給定問題并不總是那么容易,因此,本檔案是有關Redis資料型別及其最常見模式的速成課程,
對于所有示例,我們將使用該redis-cli實用程式(一個簡單但方便的命令列實用程式)對Redis服務器發出命令,
*Redis keys
Redis密鑰是二進制安全的,這意味著您可以使用任何二進制序列作為密鑰,從“ foo”之類的字串到JPEG檔案的內容,空字串也是有效的鍵,
有關密鑰的其他一些規則:
- 太長的鍵不是一個好主意,例如,1024位元組的密鑰不僅是記憶體方面的問題,也是一個壞主意,而且因為在資料集中查找密鑰可能需要進行一些代價高昂的密鑰比較,即使手頭的任務是匹配一個大值的存在,對它進行散列(例如使用SHA1)也是一個更好的主意,尤其是從記憶體和帶寬的角度來看,
- 非常短的鍵通常不是一個好主意,如果您可以改寫“ user:1000:followers”,那么將“ u1000flw”寫為密鑰毫無意義,與鍵物件本身和值物件使用的空間相比,后者更具可讀性,并且添加的空間較小,雖然短鍵顯然會消耗更少的記憶體,但您的作業是找到合適的平衡,
- 嘗試堅持使用架構,例如,“ object-type:id”是一個好主意,例如“ user:1000”,點或破折號通常用于多字欄位,例如“ comment:1234:reply.to”或“ comment:1234:reply-to”中,
- 允許的最大密鑰大小為512 MB,
*Redis Strings
Redis字串型別是您可以與Redis鍵關聯的最簡單的值型別,它是Memcached中唯一的資料型別,因此對于新手來說,在Redis中使用它也是很自然的,
由于Redis鍵是字串,因此當我們也使用字串型別作為值時,我們會將一個字串映射到另一個字串,字串資料型別對于許多用例很有用,例如快取HTML片段或頁面,
讓我們使用來處理字串型別redis-cli(所有示例將redis-cli在本教程中通過來執行),
> set mykey somevalue
OK
> get mykey
"somevalue"
如您所見,使用SET和GET命令是我們設定和檢索字串值的方式,請注意,即使鍵已與非字串值相關聯,SET仍將替換已存盤在鍵中的任何現有值,因此SET執行分配,
值可以是每種型別的字串(包括二進制資料),例如,您可以在值記憶體儲jpeg影像,值不能大于512 MB,
該SET命令有有趣的選項,這是作為附加引數,例如,如果密鑰已經存在,我可能會要求SET失敗,或者相反,只有密鑰已經存在時,它才會成功:
> set mykey newval nx
(nil)
> set mykey newval xx
OK
即使字串是Redis的基本值,您也可以使用它們執行一些有趣的操作,例如,一個是原子增量:
> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152
的INCR命令由一個決議字串值作為一個整數,它的增量,并最終將獲得的值作為新的值,還有其他類似的命令,例如INCRBY, DECR和DECRBY,在內部,它始終是相同的命令,其執行方式略有不同,
INCR是原子的意味著什么?即使使用相同密鑰發出INCR的多個客戶也永遠不會進入競爭狀態,例如,客戶端1不會同時讀取“ 10”,客戶端2會同時讀取“ 10”,都遞增為11,并將新值設定為11,最終值將始終為12,而在所有其他客戶端未同時執行命令時執行增量設定操作,
有許多用于操作字串的命令,例如,GETSET命令將鍵設定為新值,并回傳舊值作為結果,例如,如果您的系統在 每次網站接收新訪客時使用INCR遞增Redis密鑰,則可以使用此命令,您可能希望每小時收集一次此資訊,而又不會丟失任何增量,您可以GETSET鍵,為其分配新值“ 0”,然后回讀舊值,
在單個命令中設定或檢索多個鍵的值的功能對于減少延遲也很有用,因此,有MSET和MGET命令:
> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"
使用MGET時,Redis回傳一個值陣列,
*Altering and querying the key space
有些命令未在特定型別上定義,但是在與鍵的空間進行互動時很有用,因此可以與任何型別的鍵一起使用,
例如,EXISTS命令回傳1或0表示資料庫中是否存在給定的鍵,而DEL命令則洗掉鍵和關聯的值(無論該值是什么),
> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0
從示例中,您還可以看到DEL本身如何回傳1或0,具體取決于密鑰是否已洗掉(存在)(不存在具有該名稱的此類密鑰),
有許多與密鑰空間相關的命令,但是以上兩個命令與TYPE命令一起是必不可少的,TYPE命令回傳存盤在指定密鑰處的值的型別:
> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none
*Redis expires: keys with limited time to live
在繼續使用更復雜的資料結構之前,我們需要討論另一個功能,該功能不管值型別如何都可以作業,并且稱為Redis expires,基本上,您可以為密鑰設定一個超時時間,這是有限的生存時間,生存時間過去后,該密鑰將自動銷毀,就像用戶使用該密鑰呼叫DEL命令一樣,
有關Redis的一些快速資訊將過期:
- 可以使用秒或毫秒精度進行設定,
- 但是,到期時間解析度始終為1毫秒,
- 有關過期的資訊被復制并保留在磁盤上,實際上Redis服務器保持停止狀態的時間已經過去(這意味著Redis保存了密鑰過期的日期),
設定過期時間很簡單:
> set key some-value
OK
> expire key 5
(integer) 1
> get key (immediately)
"some-value"
> get key (after some time)
(nil)
由于第二次呼叫延遲了5秒鐘以上,因此在兩次GET呼叫之間密鑰消失了,在上面的示例中,我們使用EXPIRE來設定過期時間(也可以使用它來為已經具有密鑰的密鑰設定不同的過期時間,例如可以使用PERSIST來洗掉過期并使密鑰永久持久化),但是,我們也可以使用其他Redis命令來創建具有過期密鑰,例如,使用SET選項:
> set key 100 ex 10
OK
> ttl key
(integer) 9
上面的示例使用一個字串值設定一個密鑰,該密鑰100的到期時間為十秒鐘,稍后呼叫TTL命令以檢查密鑰的剩余生存時間,
為了設定和檢查以毫秒為單位到期,檢查PEXPIRE和熱釋光的命令,以及完整串列SET選項,
*Redis Lists
為了解釋List資料型別,最好從理論上入手,因為_List_一詞經常被資訊技術人員以不正當的方式使用,例如,“ Python串列”并不是名稱(鏈接串列)所建議的,而是陣列(在Ruby中,相同的資料型別實際上稱為陣列),
從非常普遍的角度來看,串列只是一系列有序元素:10,20,1,2,3是一個串列,但是,使用Array實作的List的屬性與使用_Linked List_實作的List的屬性非常不同 ,
Redis串列是通過鏈接串列實作的,這意味著即使您在串列中有數百萬個元素,在串列的開頭或結尾添加新元素的操作也會_在固定時間內_執行,使用LPUSH命令將新元素添加到具有10個元素的串列的開頭的速度與將元素添加到具有1000萬個元素的串列的開頭的速度相同,
缺點是什么?在使用Array實作的串列中,_按索引_訪問元素_的_速度非常快(恒定時間索引訪問),而在通過鏈接串列實作的串列中訪問速度不是那么快(其中操作需要的作業量與所訪問元素的索引成比例),
Redis串列是通過鏈接串列實作的,因為對于資料庫系統而言,至關重要的是能夠以非常快的方式將元素添加到很長的串列中,稍后您將看到,另一個強大的優勢是Redis串列可以在恒定的時間內以恒定的長度獲取,
當快速訪問大量元素的中間位置很重要時,可以使用另一種稱為排序集的資料結構,排序的集將在本教程的后面部分介紹,
*First steps with Redis Lists
所述LPUSH命令將一個新元素到一個串列,在左側(在頭部),而RPUSH命令將一個新元素到一個串列,在右側(在尾部),最后, LRANGE命令從串列中提取元素范圍:
> rpush mylist A
(integer) 1
> rpush mylist B
(integer) 2
> lpush mylist first
(integer) 3
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"
請注意,LRANGE需要兩個索引,要回傳的范圍的第一個和最后一個元素,兩個索引都可以為負,告訴Redis從末尾開始計數:因此-1是串列的最后一個元素,-2是串列的倒數第二個元素,依此類推,
如您所見,RPUSH在串列的右側附加了元素,而最后的LPUSH在串列的左側附加了元素,
這兩個命令都是_可變引數命令_,這意味著您可以在單個呼叫中隨意將多個元素推入串列中:
> rpush mylist 1 2 3 4 5 "foo bar"
(integer) 9
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"
4) "1"
5) "2"
6) "3"
7) "4"
8) "5"
9) "foo bar"
在Redis串列上定義的一項重要操作是_彈出元素_的能力,彈出元素是同時從串列中檢索元素并將其從串列中洗掉的操作,您可以從左側和右側彈出元素,類似于在串列兩邊推送元素的方式:
> rpush mylist a b c
(integer) 3
> rpop mylist
"c"
> rpop mylist
"b"
> rpop mylist
"a"
我們添加了三個元素并彈出了三個元素,因此在此命令序列的末尾,串列為空,沒有其他要彈出的元素,如果我們嘗試彈出另一個元素,則會得到以下結果:
> rpop mylist
(nil)
Redis回傳NULL值,以指示串列中沒有元素,
*Common use cases for lists
串列對于許多任務很有用,以下是兩個非常有代表性的用例:
- 記住用戶發布到社交網路上的最新更新,
- 使用生產者將專案推送到串列中的消費者與生產者模式進行流程之間的通信,而消費者(通常是_worker_)消耗這些專案和已執行的動作,Redis具有特殊的串列命令,以使此用例更加可靠和高效,
例如,流行的Ruby庫resque和 sidekiq都在后臺使用Redis串列,以實作后臺作業,
流行的Twitter社交網路將 用戶發布的最新推文放入Redis串列中,
為了逐步描述一個常見的用例,假設您的主頁顯示了在照片共享社交網路中發布的最新照片,并且您想加快訪問速度,
- 每次用戶發布新照片時,我們都會使用LPUSH將其ID添加到串列中,
- 當用戶訪問主頁時,我們
LRANGE 0 9為了獲取最新發布的10個專案,
*Capped lists
在許多用例中,我們只想使用串列來存盤_最新專案_,無論它們是什么:社交網路更新,日志或其他任何內容,
Redis允許我們使用串列作為上限集合,僅使用LTRIM命令記住最新的N個專案并丟棄所有最舊的專案,
的LTRIM命令類似于LRANGE,但是,而不是顯示元件的規定的范圍內將其設定在該范圍作為新的串列值,給定范圍之外的所有元素都將被洗掉,
一個例子將使其更加清楚:
> rpush mylist 1 2 3 4 5
(integer) 5
> ltrim mylist 0 2
OK
> lrange mylist 0 -1
1) "1"
2) "2"
3) "3"
上面的LTRIM命令告訴Redis僅從索引0到2列出串列元素,其他所有內容都將被丟棄,這允許一個非常簡單但有用的模式:一起執行List推操作+ List修剪操作,以便添加新元素并丟棄超出限制的元素:
LPUSH mylist <some element>
LTRIM mylist 0 999
上面的組合添加了一個新元素,并且僅將1000個最新元素納入串列,使用LRANGE,您可以訪問最重要的專案,而無需記住非常舊的資料,
注意:雖然LRANGE從技術上講是O(N)命令,但朝串列的開頭或結尾訪問較小范圍是恒定時間操作,
*Blocking operations on lists
串列具有一項特殊功能,使其適合于實作佇列,并且通常用作行程間通信系統的構建塊:阻止操作,
想象一下,您想通過一個流程將專案推入串列,然后使用不同的流程來對這些專案進行某種作業,這是通常的生產者/使用者設定,可以通過以下簡單方式實作:
- 為了將專案推送到串列中,生產者呼叫LPUSH,
- 為了從串列中提取/處理專案,消費者呼叫RPOP,
但是,有時串列可能為空,沒有任何要處理的內容,因此RPOP僅回傳NULL,在這種情況下,消費者被迫等待一段時間,然后使用RPOP重試,這稱為_輪詢_,在這種情況下不是一個好主意,因為它有幾個缺點:
- 強制Redis和客戶端處理無用的命令(串列為空時的所有請求將無法完成任何實際作業,它們只會回傳NULL),
- 由于作業人員在收到NULL之后會等待一段時間,因此會增加專案處理的延遲,為了使延遲更小,我們可以在兩次呼叫RPOP之間等待的時間更少,從而擴大了問題編號1,即對Redis的呼叫更加無用,
所以,所謂的Redis命令工具BRPOP和BLPOP它們的版本RPOP和LPOP能夠阻止如果串列是空的:他們將回到只有當新的元素添加到串列中的來電者,或在用戶指定的超時到達,
這是我們可以在worker中使用的BRPOP呼叫的示例:
> brpop tasks 5
1) "tasks"
2) "do_something"
這意味著:“等待串列中的元素tasks,但如果5秒鐘后沒有可用元素,則回傳”,
請注意,您可以將0用作超時來永遠等待元素,還可以指定多個串列,而不僅僅是一個串列,以便同時等待多個串列,并在第一個串列收到一個元素時得到通知,
有關BRPOP的幾點注意事項:
- 客戶端以有序方式提供服務:第一個阻塞等待串列的客戶端,在某個元素被其他客戶端推送時首先提供服務,依此類推,
- 回傳值與RPOP相比有所不同:它是一個包含兩個元素的陣列,因為它還包含鍵的名稱,因為BRPOP和BLPOP能夠阻止等待來自多個串列的元素,
- 如果達到超時,則回傳NULL,
關于串列和阻止操作,您應該了解更多資訊,我們建議您閱讀以下內容:
- 使用RPOPLPUSH可以構建更安全的佇列或輪換佇列,
- 該命令還有一個阻塞變體,稱為BRPOPLPUSH,
*Automatic creation and removal of keys
到目前為止,在我們的示例中,我們無需在推入元素之前創建空串列,也無需在內部不再包含元素時洗掉空串列,Redis的責任是在串列為空時洗掉鍵,或者在鍵不存在并且我們試圖向其添加元素(例如,使用LPUSH)時創建一個空串列,
這不是特定于串列的,它適用于由多個元素組成的所有Redis資料型別-流,集合,排序集合和哈希,
基本上,我們可以用三個規則來總結行為:
- 當我們將元素添加到聚合資料型別時,如果目標鍵不存在,則在添加元素之前會創建一個空的聚合資料型別,
- 當我們從聚合資料型別中洗掉元素時,如果該值保持為空,則鍵將自動銷毀,流資料型別是此規則的唯一例外,
- 呼叫帶有空鍵的只讀命令(例如LLEN(回傳串列的長度))或寫命令洗掉元素,總會產生與鍵保持空的聚合型別相同的結果,命令希望找到,
規則1的示例:
> del mylist
(integer) 1
> lpush mylist 1 2 3
(integer) 3
但是,如果密鑰存在,我們將無法對錯誤的型別執行操作:
> set foo bar
OK
> lpush foo 1 2 3
(error) WRONGTYPE Operation against a key holding the wrong kind of value
> type foo
string
規則2的示例:
> lpush mylist 1 2 3
(integer) 3
> exists mylist
(integer) 1
> lpop mylist
"3"
> lpop mylist
"2"
> lpop mylist
"1"
> exists mylist
(integer) 0
彈出所有元素后,鍵不再存在,
規則3的示例:
> del mylist
(integer) 0
> llen mylist
(integer) 0
> lpop mylist
(nil)
*Redis Hashes
Redis散列與欄位值對看起來完全一樣,可能是人們期望的“散列”外觀:
> hmset user:1000 username antirez birthyear 1977 verified 1
OK
> hget user:1000 username
"antirez"
> hget user:1000 birthyear
"1977"
> hgetall user:1000
1) "username"
2) "antirez"
3) "birthyear"
4) "1977"
5) "verified"
6) "1"
盡管哈希可以方便地表示_物件_,但是實際上可以放入哈希中的欄位數沒有實際限制(可用記憶體除外),因此您可以在應用程式內部以多種不同方式使用哈希,
HMSET命令設定哈希的多個欄位,而HGET檢索單個欄位,HMGET類似于HGET但回傳值的陣列:
> hmget user:1000 username birthyear no-such-field
1) "antirez"
2) "1977"
3) (nil)
有些命令也可以對單個欄位執行操作,例如HINCRBY:
> hincrby user:1000 birthyear 10
(integer) 1987
> hincrby user:1000 birthyear 10
(integer) 1997
您可以在檔案中找到哈希命令的完整串列,
值得注意的是,小哈希(即,一些具有較小值的元素)以特殊方式在記憶體中進行編碼,從而使它們具有很高的記憶體效率,
*Redis Sets
Redis集是字串的無序集合,該 SADD命令添加新的元素,一組,還可以對集合進行許多其他操作,例如測驗給定元素是否已存在,執行多個集合之間的交集,并集或求差等等,
> sadd myset 1 2 3
(integer) 3
> smembers myset
1. 3
2. 1
3. 2
在這里,我在集合中添加了三個元素,并告訴Redis回傳所有元素,如您所見,它們沒有排序-Redis可以在每次呼叫時隨意以任何順序回傳元素,因為與用戶之間沒有關于元素順序的約定,
Redis具有用于測驗成員資格的命令,例如,檢查元素是否存在:
> sismember myset 3
(integer) 1
> sismember myset 30
(integer) 0
“ 3”是集合的成員,而“ 30”不是集合的成員,
集合非常適合表示物件之間的關系,例如,我們可以輕松地使用集合來實作標簽,
對這個問題進行建模的一種簡單方法是為我們要標記的每個物件設定一個集合,該集合包含與物件關聯的標簽的ID,
一個例證是標記新聞文章,如果商品ID 1000帶有標簽1、2、5和77進行標記,則集合可以將這些標簽ID與新聞項相關聯:
> sadd news:1000:tags 1 2 5 77
(integer) 4
我們可能還需要逆關系:用給定標簽標記的所有新聞的串列:
> sadd tag:1:news 1000
(integer) 1
> sadd tag:2:news 1000
(integer) 1
> sadd tag:5:news 1000
(integer) 1
> sadd tag:77:news 1000
(integer) 1
要獲取給定物件的所有標簽很簡單:
> smembers news:1000:tags
1. 5
2. 1
3. 77
4. 2
注意:在示例中,我們假設您具有另一個資料結構,例如Redis哈希,它將標簽ID映射到標簽名稱,
還有其他一些非常簡單的操作,使用正確的Redis命令仍然很容易實作,例如,我們可能需要包含標簽1、2、10和27的所有物件的串列,我們可以使用SINTER命令執行此操作,該命令執行不同集合之間的交集,我們可以用:
> sinter tag:1:news tag:2:news tag:10:news tag:27:news
... results here ...
除了交集之外,您還可以執行并集,求差,提取隨機元素等等,
提取元素的命令稱為SPOP,對于建模某些問題非常方便,例如,為了實作基于Web的撲克游戲,您可能需要用一組來代表您的套牌,假設我們對(C)lubs,(D)鉆石,(H)耳釘,(S)墊使用一個單字符前綴:
> sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
S7 S8 S9 S10 SJ SQ SK
(integer) 52
現在我們要為每個玩家提供5張卡片,該SPOP命令洗掉一個隨機元素,將其回傳到客戶端,所以在這種情況下完美運行,
但是,如果我們直接在甲板上對其進行稱呼,那么在游戲的下一場比賽中,我們將需要再次填充紙牌,這可能并不理想,因此,首先,我們可以將存盤在deck密鑰中的集合復制到game:1:deck密鑰中,
這可以使用SUNIONSTORE來完成,SUNIONSTORE通常執行多個集合之間的聯合,并將結果存盤到另一個集合中,但是,由于單個集合的并集本身,我可以使用以下命令復制我的卡組:
> sunionstore game:1:deck deck
(integer) 52
現在,我準備為第一位玩家提供五張牌:
> spop game:1:deck
"C6"
> spop game:1:deck
"CQ"
> spop game:1:deck
"D1"
> spop game:1:deck
"CJ"
> spop game:1:deck
"SJ"
一副千斤頂,不是很好...
現在是引入set命令的好時機,該命令提供集合中元素的數量, 在集合理論的背景關系中,這通常稱為_集合_的_基數_,因此Redis命令稱為SCARD,
> scard game:1:deck
(integer) 47
數學原理:52-5 = 47,
當您只需要獲取隨機元素而不將其從集合中洗掉時,可以使用適合該任務的SRANDMEMBER命令,它還具有回傳重復元素和非重復元素的功能,
*Redis Sorted sets
排序集是一種資料型別,類似于集合和哈希之間的混合,像集合一樣,排序集合由唯一的,非重復的字串元素組成,因此從某種意義上說,排序集合也是一個集合,
但是,雖然集內的元素沒有排序,但排序后的集合中的每個元素都與一個稱為_得分_的浮點值相關聯 (這就是為什么該型別也類似于哈希的原因,因為每個元素都映射到一個值),
此外,已排序集合中的元素是按_順序進行的_(因此,它們不是應請求而排序的,順序是用于表示已排序集合的資料結構的特殊性),它們按照以下規則排序:
- 如果A和B是兩個分數不同的元素,則如果A.score是> B.score,則A>B,
- 如果A和B的分數完全相同,那么如果A字串在字典上大于B字串,則A>B,A和B字串不能相等,因為排序集僅具有唯一元素,
讓我們從一個簡單的示例開始,添加一些選定的黑客名稱作為排序的集合元素,并以其出生年份為“得分”,
> zadd hackers 1940 "Alan Kay"
(integer) 1
> zadd hackers 1957 "Sophie Wilson"
(integer) 1
> zadd hackers 1953 "Richard Stallman"
(integer) 1
> zadd hackers 1949 "Anita Borg"
(integer) 1
> zadd hackers 1965 "Yukihiro Matsumoto"
(integer) 1
> zadd hackers 1914 "Hedy Lamarr"
(integer) 1
> zadd hackers 1916 "Claude Shannon"
(integer) 1
> zadd hackers 1969 "Linus Torvalds"
(integer) 1
> zadd hackers 1912 "Alan Turing"
(integer) 1
如您所見,ZADD與SADD相似,但是使用一個額外的引數(放置在要添加的元素之前)作為得分, ZADD也是可變引數,因此即使上面的示例中未使用它,您也可以自由指定多個得分-值對,
使用排序集,回傳按其出生年份排序的黑客串列很簡單,因為實際上_他們已經被排序了_,
實施說明:排序集是通過包含跳過串列和哈希表的雙埠資料結構實作的,因此,每次添加元素時,Redis都會執行O(log(N))操作,很好,但是當我們要求排序元素時,Redis根本不需要做任何作業,它已經全部排序了:
> zrange hackers 0 -1
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"
6) "Richard Stallman"
7) "Sophie Wilson"
8) "Yukihiro Matsumoto"
9) "Linus Torvalds"
注意:0和-1表示從元素索引0到最后一個元素(-1的作業方式與LRANGE命令的情況相同),
如果我想按相反的順序訂購(最小到最大)怎么辦?使用ZREVRANGE而不是ZRANGE:
> zrevrange hackers 0 -1
1) "Linus Torvalds"
2) "Yukihiro Matsumoto"
3) "Sophie Wilson"
4) "Richard Stallman"
5) "Anita Borg"
6) "Alan Kay"
7) "Claude Shannon"
8) "Hedy Lamarr"
9) "Alan Turing"
也可以使用以下WITHSCORES引數回傳分數:
> zrange hackers 0 -1 withscores
1) "Alan Turing"
2) "1912"
3) "Hedy Lamarr"
4) "1914"
5) "Claude Shannon"
6) "1916"
7) "Alan Kay"
8) "1940"
9) "Anita Borg"
10) "1949"
11) "Richard Stallman"
12) "1953"
13) "Sophie Wilson"
14) "1957"
15) "Yukihiro Matsumoto"
16) "1965"
17) "Linus Torvalds"
18) "1969"
*Operating on ranges
排序集比這更強大,它們可以在范圍內操作,讓我們獲取所有在1950年(含)之前出生的人,我們使用ZRANGEBYSCORE命令來做到這一點:
> zrangebyscore hackers -inf 1950
1) "Alan Turing"
2) "Hedy Lamarr"
3) "Claude Shannon"
4) "Alan Kay"
5) "Anita Borg"
我們要求Redis回傳分數在負無窮大和1950之間的所有元素(包括兩個極端),
也可以洗掉元素范圍,讓我們從排序集中洗掉所有1940年至1960年之間出生的黑客:
> zremrangebyscore hackers 1940 1960
(integer) 4
ZREMRANGEBYSCORE可能不是最好的命令名稱,但是它可能非常有用,并回傳已洗掉元素的數量,
為排序的集合元素定義的另一個極其有用的操作是get-rank操作,可以問一個元素在有序元素集合中的位置是什么,
> zrank hackers "Anita Borg"
(integer) 4
該ZREVRANK命令也可以為了獲得軍銜,考慮的要素排序的下降方式,
*Lexicographical scores
在最新版本的Redis 2.8中,引入了一項新功能,該功能允許按字典順序獲取范圍,假設已排序集中的元素都以相同的相同分數插入(將元素與C memcmp函式進行比較 ,因此可以確保沒有排序規則) ,并且每個Redis實體將以相同的輸出進行回復),
用于按字典順序操作的主要命令是ZRANGEBYLEX, ZREVRANGEBYLEX,ZREMRANGEBYLEX和ZLEXCOUNT,
例如,讓我們再次添加我們的著名黑客串列,但是這次對所有元素使用零分:
> zadd hackers 0 "Alan Kay" 0 "Sophie Wilson" 0 "Richard Stallman" 0
"Anita Borg" 0 "Yukihiro Matsumoto" 0 "Hedy Lamarr" 0 "Claude Shannon"
0 "Linus Torvalds" 0 "Alan Turing"
由于排序集的排序規則,它們已經按字典順序排序:
> zrange hackers 0 -1
1) "Alan Kay"
2) "Alan Turing"
3) "Anita Borg"
4) "Claude Shannon"
5) "Hedy Lamarr"
6) "Linus Torvalds"
7) "Richard Stallman"
8) "Sophie Wilson"
9) "Yukihiro Matsumoto"
使用ZRANGEBYLEX我們可以要求詞典范圍:
> zrangebylex hackers [B [P
1) "Claude Shannon"
2) "Hedy Lamarr"
3) "Linus Torvalds"
范圍可以是包含(inclusive)或排除(exclusive)(取決于第一個字符),字串無限和負無限分別用+和-字串指定,有關更多資訊,請參見檔案,
此功能非常重要,因為它允許我們將排序后的集合用作通用索引,例如,如果要通過128位無符號整數引數索引元素,則只需將元素添加到具有相同分數(例如0)但具有由128個位元組組成的16位元組前綴的排序集中大尾數中的位數,由于big endian中的數字實際上按數字順序也按字典順序(以原始位元組順序)排序,因此您可以要求128位空間中的范圍,并獲得丟棄前綴的元素值,
如果要在更嚴重的演示環境中查看該功能,請檢查Redis自動完成演示,
*Updating the score: leader boards
在切換到下一個主題之前,請只對已排序集做最后的說明,排序集的分數可以隨時更新,只需對已包含在排序集中的元素呼叫ZADD,將以O(log(N))時間復雜度更新其得分(和位置),這樣,當有大量更新時,排序集是合適的,
由于這種特性,常見的用例是排行榜,典型的應用是Facebook游戲,您可以將按高分對用戶進行排序的能力與獲得排名的操作結合起來,以顯示前N名的用戶以及排行榜中的用戶排名(例如,“您是這里的#4932最佳成績”),
*Bitmaps
位圖不是實際的資料型別,而是在String型別上定義的一組面向位的操作,由于字串是二進制安全Blob,并且最大長度為512 MB,因此它們適合設定多達2 32個不同的位,
位操作分為兩類:固定時間的單個位操作(如將一個位設定為1或0或獲取其值),以及對位組的操作,例如計算給定位范圍內設定的位的數量(例如,人口計數),
位圖的最大優點之一是,它們在存盤資訊時通常可以節省大量空間,例如,在以增量用戶ID表示不同用戶的系統中,僅使用512 MB記憶體就可以記住40億用戶的一位資訊(例如,知道用戶是否要接收新聞通訊),
使用SETBIT和GETBIT命令設定和檢索位:
> setbit key 10 1
(integer) 1
> getbit key 10
(integer) 1
> getbit key 11
(integer) 0
所述SETBIT命令采用作為第一個引數的位元數,和作為第二個引數的值以設定所述位,其為1或0的命令自動放大字串,如果尋址位是當前字串長度之外,
GETBIT只是回傳指定索引處的位的值,超出范圍的位(尋址超出存盤在目標鍵中的字串長度的位)始終被視為零,
在位組上有三個命令:
- BITOP在不同的字串之間執行按位運算,提供的運算為AND,OR,XOR和NOT,
- BITCOUNT執行填充計數,報告設定為1的位數,
- BITPOS查找指定值為0或1的第一位,
無論BITPOS和位元計數能夠與字串的位元組范圍進行操作,而不是該字串的整個長度運行,以下是BITCOUNT呼叫的一個簡單示例:
> setbit key 0 1
(integer) 0
> setbit key 100 1
(integer) 0
> bitcount key
(integer) 2
位圖的常見用例是:
- 各種實時分析,
- 存盤與物件ID相關的空間高效但高性能的布爾資訊,
例如,假設您想知道網站用戶每天訪問量最長的時間,您從零開始計算天數,即從您公開網站的那一天開始,并在用戶每次訪問該網站時對SETBIT進行設定,作為位索引,您只需花費當前的unix時間,減去初始偏移量,然后除以一天中的秒數(通常為3600 * 24),
這樣,對于每個用戶,您都有一個小的字串,其中包含每天的訪問資訊,使用BITCOUNT,可以輕松獲得給定用戶訪問網站的天數,而只需幾個BITPOS呼叫,或者僅獲取和分析客戶端的位圖,就可以輕松計算最長的連勝記錄,
位圖很容易分成多個鍵,例如,為了分片資料集,并且因為通常最好避免使用大鍵,要在不同的密鑰上拆分位圖,而不是將所有位都設定為密鑰,一個簡單的策略就是為每個密鑰存盤M位,并使用來獲取密鑰名稱,使用來獲取bit-number/M第N位bit-number MOD M,
*HyperLogLogs
HyperLogLog是一種概率資料結構,用于對唯一事物進行計數(從技術上講,這是指估計集合的基數),通常,對唯一專案進行計數需要使用與要計數的專案數量成比例的記憶體量,因為您需要記住過去已經看到的元素,以避免多次對其進行計數,但是,有一組演算法會以記憶體為代價來交換精度:您最侄訓得到帶有標準誤差的估計量度,在Redis實作的情況下,該誤差小于1%,這種演算法的神奇之處在于,您不再需要使用與所計數專案數量成正比的記憶體量,而是可以使用恒定數量的記憶體!在最壞的情況下為12k位元組,如果您的HyperLogLog(從現在開始將它們稱為HLL)看到的元素很少,則少得多,
Redis中的HLL盡管在技術上是不同的資料結構,但被編碼為Redis字串,因此您可以呼叫GET來序列化HLL,然后呼叫SET 來將其反序列化回服務器,
從概念上講,HLL API就像使用Set來執行相同的任務,你會 薩德每個觀測元素為一組,并且將使用SCARD檢查組中的元素,這是唯一的數量自SADD不會再添加一個現有的元素,
盡管您并未真正_將專案添加_到HLL中,但由于資料結構僅包含不包含實際元素的狀態,因此API相同:
-
每次看到新元素時,都可以使用PFADD將其添加到計數中,
-
到目前為止,每次您要檢索_添加_到PFADD的唯一元素的當前近似值時,都可以使用PFCOUNT,
> pfadd hll a b c d (integer) 1 > pfcount hll (integer) 4
該資料結構用例的一個例子是每天計算用戶在搜索表單中執行的唯一查詢,
Redis也能夠執行HLL的合并,請查看 完整的檔案以獲取更多資訊,
*Other notable features
Redis API中還有其他重要內容,在本檔案的背景關系中無法探討,但值得您注意:
- 可以逐步迭代大型集合的鍵空間,
- 可以在服務器端運行Lua腳本以改善延遲和帶寬,
- Redis還是Pub-Sub服務器,
*Learn more
本教程絕不完整,僅涵蓋了API的基礎知識,閱讀命令參考以發現更多內容,
感謝您的閱讀,并祝您使用Redis玩得開心!
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/2457.html
標籤:NoSQL
