中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

redis數據結構有哪些內容

發布時間:2021-12-23 09:35:07 來源:億速云 閱讀:161 作者:iii 欄目:數據庫

本篇內容主要講解“redis數據結構有哪些內容”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“redis數據結構有哪些內容”吧!

redis不只是一個簡單的鍵(key)-值(value)數據庫,實際上它是一個數據結構服務器,支持各種類型的值。也就是說,在傳統的鍵-值數據庫中,你把字符串鍵與字符串值聯系起來,而在redis,值不僅限于一個簡單的字符串,還可以是更復雜的數據結構。下面列出了所有redis支持的數據結構,下文會分別對這些結構進行介紹:

  • 二進制安全字符串

  • 隊列(lists):基于插入順序有序存儲的字符串元素集合。主要是鏈式的list。

  • 集(sets):元素唯一的、無序的字符串元素集合。

  • 有序集(sorted sets):與sets相似,但是每個字符串元素都與一個被稱為分數(score)的浮點數相關聯。和sets不同的是,元素能夠基于分數排序,因此可以檢索某個范圍內的元素(比如你可以查詢前10個或后10個)。

  • 哈希(hashes):由域(fields)和值之間關系組成的映射。域和值都是字符串。這和Ruby或Python的哈希非常相似。

  • 位數組(位圖bitmaps):可以通過特殊命令,像處理位圖一樣地處理字符串:設置和清除某一位,統計被置1的位數,找到第一個被設置或沒有被設置的位等。

  • HyperLogLogs:這是一種概率數據結構,用于估算集的勢。不要被嚇到了,沒那么難。本文將在下文中HyperLogLog章節介紹。

遇到問題的時候,理解數據結構是怎么工作的以及怎么被使用的并不是那么微不足道的事情。因此,這篇文檔是一個關于Redis數據類型和它們常用模式的速成教材。 
這里所有的例子,我們都使用redis客戶端(redis-cli)。相對于redis服務器來說,這是一個簡單方便的命令行控制臺。

redis的鍵

redis的鍵是二進制安全【1】的,也說是說,你可以使用任意的二進制序列作為鍵,比如字符串”foo”或一個JPEG文件的內容。 
空串也是一個有效的鍵。 
一些關于鍵的其它規則:

  • 太長的鍵不推薦。例如長度為1024字節的鍵并不好,不管是從內存角度,還是從查詢鍵的角度。因為從數據集中查詢鍵需要多次的鍵匹配步驟。即使手邊的任務就是要判斷一個很大的值是否存在,采用某種手段對它做hash是個好主意,尤其是從內存和帶寬的角度去考慮。

  • 太短的鍵通常也不推薦。如果你把鍵“user:1000:followers”寫成“u1000flw”可能會有點問題。因為前者可讀性更好,而只需要多花費一點點的空間。短的鍵顯然占的花費的空間會小一點,因此你需要找到平衡點。

  • 盡量堅持模式。例如”object-type:id”是推薦的,就像”user:1000”。點和短線常用于多個單詞的場景,比如”comment:1234:reply.to”或”comment:1234:reply-to”。

  • 鍵的大小不能超過512MB。

Redis中的字符串

Redis中的字符串類型是可以與鍵關聯的最簡單的類型。它中Memcached中唯一的數據類型,也是Redis新手最常用的類型。 
由于Redis的鍵都是字符串,那么把使用字符串為值,也就是字符串到字符串的映射。字符串數據類型可以用于許多場景,比如緩存HTML片段或頁面。 
讓我們用redis客戶端嘗試一些字符串類型的使用吧(本文所有的例子都在redis客戶端執行)。

> set mykey somevalueOK> get mykey"somevalue"

正如你所看到的,GET和SET命令用于設置或獲取一個字符串值。需要注意的是,如果鍵已經存在,SET會覆蓋它的值,即使與這個鍵相關聯的不是字符串類型的值。SET相當于賦值。 
值可以是任意類型的字符串(包含二進制數據),你也可以使用一個jpeg圖像。值在大小不能大于512MB。 
SET命令配上一些額外的參數,可以實現一些有趣的功能。例如,我可以要求如果鍵已經存在,SET就會失敗,或者相反,鍵已經存在時SET才會成功。

> set mykey newval nx(nil)> set mykey newval xxOK

雖然字符串是最基礎的數據類型,你仍可以對它執行一些有趣的操作,比如原子性的自增:

> set counter 100OK> incr counter(integer) 101> incr counter(integer) 102> incrby counter 50(integer) 152

INCR命令把字符串解析成一個整數,然后+1,把得到的結果作為一個新值存進去。還有其它相似的命令:INCRBY, DECR, DECRBY。從命令的實現原理上講,這幾個命令是相同的,只是有一點細微的差別。 
為什么說INCR是原子性的呢?因為即使是多個客戶端對同一個鍵使用INCR命令,也不會形成競爭條件。舉個例子,像這樣的情況是不會發生的:客戶端1讀取到鍵是10,客戶端2也讀到鍵值是10,它們同時對它執行自增命令,最終得到的值是11。實際上,最終的得到的值是12,因為當一個客戶端對鍵值做讀-自增-寫的過程中,其它的客戶是不能同時執行這個過程的。 
有許多用于操作字符串的命令,例如GETSET命令,它給鍵設置一個新值,并返回舊值。比如你有一個系統,每當有一個新的訪問者登陸你的網站時,使用INCR對一個鍵值自增。你可能想要統計每個小時的信息,卻又不希望丟失每次自增操作。你可以使用GETSET命令,設置一個新值“0”,同時讀取舊值。 
redis支持通過一條命令同時設置或讀取多個鍵,這對于減少延時很有用。這就是MSET命令和MGET命令:

> mset a 10 b 20 c 30OK> mget a b c1) "10"
2) "20"
3) "30"

使用MGET時,redis返回包含多個值的數組。

更改或查詢鍵空間

【2】 
有些命令并沒有指定特定的類型,但在與鍵空間的交互有非常有用,因此可以用于任意類型的鍵。 
舉個例子,EXISTS命令返回1或者0,用于表示某個給定的鍵在數據庫中是否存在。DEL命令刪除鍵以及它對應的值而不管是什么值。

> set mykey helloOK> exists mykey(integer) 1> del mykey(integer) 1> exists mykey(integer) 0

DEL返回1還是0取決于鍵是(鍵存在)否(鍵不存在)被刪除掉了。 
有許多鍵空間相關的命令,但以上這兩個命令和TYPE命令是最基本的。TYPE命令的作用是返回這個鍵的值的類型。

> set mykey xOK> type mykeystring> del mykey(integer) 1> type mykeynone

鍵的生命周期

在介紹更多更復雜的數據結構之間,我們先討論另一個與值類型無關的特性,那就是redis的期限(redis expires)。最基本的,你可以給鍵設置一個超時時間,就是這個鍵的生存周期。當生存周期過去了,鍵會被自動銷毀,就好像被用戶執行過DEL一樣。 
一些關于redis期限的快速信息:

  • 生存周期可以設置的時間單位從秒級到毫秒級。

  • 生存周期的時間精度都是1毫秒。

  • 關于生存周期的數據有多份且存在硬盤上,基于Redis服務器停止了,時間仍在流逝,這意味著redis存儲的是key到期的時間。

設置生存周期是件瑣碎的事情:

> set key some-valueOK> expire key 5(integer) 1> get key (immediately)"some-value"> get key (after some time)(nil)

鍵在兩次調用之間消失了,這是因為第二次調用的延遲了超過5秒的時間。在上面的例子中,我們使用EXPIRE命令設置生命周期(它也可以用于為一個已經設置過生命周期的鍵重新設置生命周期,PERSIST命令可以用于移除鍵的命令周期,使它能夠長期存在)。我們還可以使用redis命令在創建鍵的同時設置生命周期。比如使用帶參數的SET命令:

> set key 100 ex 10OK> ttl key(integer) 9

上面這個例子中創建了一個鍵,它的值是字符串100,生命周期是10秒。后面的TTL命令用于查看鍵的剩余時間。 
如果要以毫秒為單位設置或查詢鍵的生命周期,請查詢PEXPIRE命令和PTTL命令,以及SET命令的參數列表。

redis中的列表(lists)

要解釋列表數據類型,最好先從一點理論開始。因為列表這個術語常被信息技術人員錯誤地使用。例如“python 列表”,并不像它的命令所提示的(鏈表),而是數組(實際上與Ruby中的數組是同一個數據類型)。 
從廣義上講,列表只是元素的有序序列:10,20,1,2,3是一個列表。但是用數組實現的列表和用鏈表實現的列表,它們的屬性有很大的不同。 
redis的列表都是用鏈表的方式實現的。也就是說,即使列表中有數百萬個元素,增加一個新元素到列表頭部或尾部操作的執行時間是常數時間。使用LPUSH命令把一個新元素增加到一個擁有10個元素的列表的頭部,或是增加到一個擁有一千萬個元素的列表的頭部,其速度是一樣的。 
缺點是什么呢?通過索引訪問一個元素的操作,在數組實現的列表中非常快(常數時間),但在鏈表實現的列表中不是那么快(與找到元素對應下標的速度成比例)。 
redis選擇用鏈表實現列表,因為對于一個數據庫來說,快速地向一個很大的列表新增元素是非常重要的。另一個使用鏈表的強大優勢,你稍后將會看到,能夠在常數時間內得到一個固定長度的redis列表。 
快速地讀取很大一堆元素的中間元素也是重要的,這時可以使用另一種數據結構,稱為有序集(sorted sets)。本文后面會講到有序集。

regis列表第一步

LPUSH命令把一個新的元素加到列表的左邊(頭部),而RPUSH命令把一個新的元素加到列表的右邊(尾部)。LRANGE命令從列表中提取某個范圍內的元素

> rpush mylist A(integer) 1> rpush mylist B(integer) 2> lpush mylist first(integer) 3> lrange mylist 0 -11) "first"
2) "A"
3) "B"

注意,LRANGE命令需要輸入兩個下標,即范圍的第一個元素下標和最后一個元素下標。兩個下標都可以是負的,意思是從尾部開始數:因此-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返回空值說明列表中沒有元素了。

列表的常見用例

列表可以用于完成多種任務,以下是兩個非常有代表性的用例:

  • 記住用戶發布到社交網絡的最新更新。

  • 使用消費者-生產者模型進行進程間通信,生產生把表項(items)放進列表中,消費者(通常是工作者)消費這些items并執行一些行為。redis針對這種用例有一些特殊的列表命令,既可靠又高效。

例如非常有名的Ruby庫resque和sidekip,在底層都使用了Redis列表來實現后臺作業。 
著名的社交網絡Twitter使用Redis列表來獲取用戶發布的最新的消息。 
為了一步一步地描述一個常見用例,假設要在你的主頁上展示社交網絡上最新分享的照片并且加速訪問。

  • 每當一個用戶發布了一張新的照片,我們使用LPUSH命令把它的ID加入到列表中。

  • 當用戶訪問這個主頁,我們使用LRANGE 0 9獲取最新加入的10個表項。

限制列表

很多情況下我們只想要使用列表來存儲最新的幾條表項,例如社交網絡更新、日志或者其它。 
Redis允許我們使用列表作為一個固定集合,使用LTRIM命令,只記錄最新的N條記錄,而丟棄所有更早的記錄。 
LTRIM命令和LRANGE命令相似,但不像LRANGE一樣顯示特定范圍的元素,而是用這個范圍內的值重新設置列表。所有范圍外的元素都被刪除了。 
用個例子來說明這一點:

> rpush mylist 1 2 3 4 5(integer) 5> ltrim mylist 0 2OK> lrange mylist 0 -11) "1"
2) "2"
3) "3"

上面的LTRIM命令告訴Redis只取得列表中下標為0到2的元素,其它的都要丟棄。這就是一種簡單有用的模式成為了可能:列表增加(push)元素操作+列表提取(trim)元素操作=增加一個元素同時刪除一個元素使得列表元素總數有限:

LPUSH mylist <some element>LTRIM mylist 0 999

上面的操作結合增加一個元素但只是存在1000個最新的元素在列表中。通過LRANGE你可以獲取最新的表項而不需要記住舊的數據。 
注意:由于理論上LRANGE是O(N)命令,讀取從頭開始或從尾開始的小范圍數據是常數時間的操作。

列表中是阻塞型操作

列表的一些特性使它適合現實隊列(queues),也通常作為進程間通信系統的一個基礎組件:阻塞式操作。 
假設你通過一個進程把元素增加到列表中,使用另一個進程對這些元素做些實際的操作。這是通常的生產者/消費者基礎,你可以用下面這種簡單的方法實現:

  • 生產者調用LPUSH,把元素加入列表

  • 消費者調用RPOP,把元素從列表中取出或處理

有沒有可能出現這種情況,列表是空的,沒有什么東西可以處理,因此RPOP返回NULL。這種情況下,消費者不得不等一會再嘗試RPOP。這就叫輪詢。這并不是一個好方法,因為它有以下缺點:

  1. 要求redis和客戶端執行沒有意義的命令(當列表為空是所有的請求都不會執行實際工作,只是返回NULL)

  2. 工作者在收到NULL之后加入一個延時,讓它等待一些時間。如果讓延時小一點,在兩次調用RPOP之間的等待時間會比較短,這成為第一個問題的放大-調用Redis更加沒有意義

因此Redis實現了命令BRPOP和BLPOP,它是RPOP和LPOP的帶阻塞功能的版本:當列表為空時,它們會等到一個新的元素加入到列表時,或者用戶定義的等待時間到了時,才會返回。 
這是BRPOP調用的一個例子,我們可以在工作者進程使用它:

> brpop tasks 5
1) "tasks"2) "do_something"

它的意思是:等待列表中的元素,如果5秒還沒有可用的元素。 
注意,如果使用0作為超時時間,將會永遠等待,你也可以定義多個列表而不只是一個,這樣就會同時等待多個列表,當任意一個列表收到一個元素時就會收到通知。 
一些關于BRPOP需要注意的事情:

  1. 客戶端是按順序被服務的:第一個等待某個列表的客戶端,當列表被另一個客戶端增加一個元素時,它會第一個處理。

  2. 返回值與RPOP的不同:只得到兩個元素的包含鍵名的數組,因為BRPOP和BLPOP因為等待多個列表而阻塞。

  3. 如果時間超時了,就會返回NULL

還有更多你應該知道的關于列表和阻塞操作的東西。我們建議你閱讀以下材料:

  • 可以使用RPOPLPUSH創建更安全的隊列或旋轉隊列。

  • 這個命令有一個阻塞參數,即BRPOPLPUSH

自動創建和移除鍵

到目前為止我們的例子還沒有涉及到這些情景,在增加一個元素之間創建一個空的列表,或者當一個列表沒有元素時把它移除。redis有責任刪除變為空的列表,或當我們試圖增加元素時創建空列表。例如LPUSH 
這不僅適用于列表,它可以應用于所有包含多個元素的Redis數據結構-集、有序集和哈希。 
基本上講,我們把它的行為總結為三個規則:

  1. 當我們把一個元素增加到一個集合類數據類型時,如果這個鍵不存在,在增加前會創建一個空的集合類數據類型。

  2. 我們從一個集合類數據類型中移除一個元素時,如果值保持為空,鍵就會被自動刪除

  3. 調用一個只讀命令例如LLEN(返回列表的長度),或者一個移除元素的寫命令但鍵為空,結果不會改變。[3]

規則1舉例:

> del mylist(integer) 1> lpush mylist 1 2 3(integer) 3

然而,我們不能對一個已經存在的鍵執行與它類型不同的操作:

> set foo barOK> lpush foo 1 2 3(error) WRONGTYPE Operation against a key holding the wrong kind of value> type foostring

規則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中的哈希(hashed)

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"

hash表示對象(object)非常方便。實際上,可以放入一個hash的域的數量沒有限制(不考慮可用內存),因此你可以在你的應用中用許多不同的方式使用哈希。 
HMSET命令為hash設置多個域,而HGET獲取某一個域。HMGET和HGET相似,但它返回由值組成的數組。

> hmget user:1000 username birthyear no-such-field1) "antirez"2) "1977"3) (nil)

還有一些命令可以對單個的域執行操作,例如HINCRBY:

> hincrby user:1000 birthyear 10(integer) 1987> hincrby user:1000 birthyear 10(integer) 1997

你可以查看這篇文檔《hash命令全列》 
把小的哈希(少量的元素,較小的值)用特殊的編碼方式存放在內存中并不是什么難事,因此它們的空間效率非常高。

redis的集(sets)

Redis的集是字符串無序的集合。SADD向集中增加一些元素。對于集合還有很多其它的操作,例如測試某個給定的元素是否存在,多個集合之間求交集、合集或者差集,等。

> sadd myset 1 2 3(integer) 3> smembers myset1. 32. 13. 2

在這個例子中,我向myset中增加了三個元素,并讓redis返回所有的元素。正如你所看到的,它們是無序的。每次調用,redis都可能以任何順序返回元素,因此在這里,用戶不能對元素的順序有要求。 
redis提供測試成員的命令。這個給定的元素是否存在?

> sismember myset 3(integer) 1> sismember myset 30(integer) 0

“3”是這個集中的一員,而“30”不是。 
集善于表現對象之間的關系。例如我們可以很容易使用集實現標簽(tags)。處理這個問題的一個簡單的模型就是把所有要打標簽的對象設置一個集。集包含相關對象的標簽的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:tags1. 52. 13. 774. 2

注意:在這個例子中我們假設你還有另一個數據結構,例如redis的哈希,用于標簽ID到標簽名的映射。 
如果使用正確的redis命令,可以通過并不繁瑣卻簡單的方式去實現。例如我們可能想到同時擁有1,2,10和27標簽的所有對象。我們可以使用SINTER命令執行不同集之間的求交運算。我們可以這么用:

> sinter tag:1:news tag:2:news tag:10:news tag:27:news... results here ...

求交集運算不是唯一可以執行的操作,你還可以執行求并集運算、求差集運算、提取任意一個元素等。 
提取一個元素的命令是SOP,它對于模擬某些問題很方便。例如要實現一個基于網頁的撲克牌游戲,你可能會把你的牌(deck)做成一個集。假設我們使用一個字符前綴來表示C(梅花)、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調用它,下一輪游戲我們需要把再次填寫所有的牌,這還不夠理想。因此在開始之前,先把集中存儲的deck鍵做一個備份到game中。使用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"

一對J,不太好。。。 
現在是時候介紹集中元素個數的命令了。在集理論中,元素個數常被為集的勢,因此這個命令是SCARD。

> scard game:1:deck(integer) 47

計算公式:52-5=47 
如果你只是想得到一個隨機的元素但不把它從集中刪除,SRANDMEMBER命令適合這個任務。它還可以提供返回重復元素或非重要元素的功能。

Redis的有序集

有序集像一種將集和哈希混合的數據類型。像集一樣,有序集由唯一的不重復的字符串元素組成。因此某種意義上說,有序集也是一個集。 
集中的元素是無序的,而有序集中的元素都基于一個相關聯的浮點值排序。這個浮點值稱為分數(score)(每個元素都映射到一個值,因此和哈希相似)。 
此外,有序集中的元素是按順序取的(它們不是按照要求排序的,排序是這個數據結構用于表現有序集的一個特性【4】)。它們按照下面的規則排序:

  • 假設A和B是分值不同的兩個元素,如果A的分數>B的分數,則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
  • 1

正如你所見,ZADD和SADD相似,但是需要一個額外的參數(位置在要加的元素之前),這就是分數。ZADD也是參數可變的,你可以隨意地定義多個“分數-值”對,雖然上面的例子沒有這么寫。 
要求有序集中的黑客名單按他們的出生年份排序是沒有意義的,因為它們已經是這樣的了。 
實現細節:有序集是基于一個雙端口數據結構實現的,包含一個跳躍表和一個哈希表。因此增加一個元素的執行時間是O(log(N))。這很好,當我們請求有序的元素時不需要其它的工作,它們已經是排序的了:

> 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命令中的-1一樣)。 
如果想要反向排序,從最年輕到最老呢?使用ZREVERANGE代替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"

基于范圍的操作

有序集的功能強大遠不止這些。它還可以基于范圍操作。我們要取得所有出生年份早于(包括)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命令也可以獲取排名,不過元素是逆序排序的。

字典序的分數

最近的Redis 2.8版本引入了一個新特性,假設有序集中所有元素的分數相同(使用C語言的memcmp函數來比較元素,這樣保證每個redis實例都會返回相同的結果)的情況下,允許按照字典序獲得范圍。【5】 
針對字典序范圍操作的主要命令是ZRANGEBYLEX、ZREVRANGEBYLEX、ZREMRANGEBYLEX和ZLEXCOUNT。 
舉個例子,我們再次把所有著名黑客加入到列表中,但這一次所有元素的分數都是0:

> 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"

范圍是開區間還是閉區間都可以(由第一個字符決定),字符串正無窮和負無窮分別通過+和-來定義。更多信息請查看文檔。 
這個特性很重要,它使得我們使用有序集作為一個通常索引。舉個例子,如果你想要使用一個128位的無符號整數來為元素索引,你所要做的只是把元素加入到一個有序集并設置一個相同的分數(比如0)以及一個由128位數值組成的8字節前綴。由于數值是大端的,字典序的順序(原始字節序)實際上是數字序的,你可以在128位空間請求范圍,以前綴降序返回元素的值。 
如果你想查看這個特性更嚴謹的演示,請查看 Redis autocomplete demo.

更新分數:排行榜

這是在切換到下一個話題之前最后一個關于有序集的點。有序集的分數可以隨時被更新。只需要對一個在有序集中已經存在的元素執行ZADD就可以在O(log(N))更新它的分數(和位置)。同樣的,當會經常更新時使用有序集非常合適。 
這個特性的一個通常用例是排行榜。典型的應用是Facebook的一個游戲,你可以使用戶基于它們的高分排序,增加獲取排名的操作,在排行榜上顯示前N個用戶及用戶排名(例:你是第4932好的分數)

位圖

位圖其實不是一個真正的數據類型,只是在這種字符串類型上有一系列基于位的操作。由于字符串是二進制安全的,最大長度是512MB,因此可以設置多達2^32種不同的位串。 
位操作分為兩類,一種是針對某一個位的常數時間操作,如果設置某個位為1或0,或獲取某個位的值。另一種是對所有位的操作,例如計算一個給定范圍內被設置為1的位的個數(如人數統計)。 
位圖一個最大的優勢就是存儲信息時非常少空間。例如一個系統里面每個用戶用一個不同的遞增的用戶ID表示,可以記錄40億用戶的某個信息(這個用戶是否想要接收郵件)只需要512M的內存。 
通過SETBIT命令和GETBIT命令設置或獲取位:

> setbit key 10 1(integer) 1> getbit key 10(integer) 1> getbit key 11(integer) 0

SETBIT命令把第一個參數作為位的序號,第二個參數作為這個位要設置的值,只能是1或0。如果地址位大于當前字符串的長度,這個命令會自動擴充字符串。 
GETBIT只返回位于某個位置的值。超過長度的位(地址位大于字符串的長度)將必然得到0。 
這三個命令是對所有位的操作:

  1. BITOP:執行不同字符串之間的位操作。包括AND、OR、XOR和NOT。

  2. BITCOUNT:執行統計操作,返回位集中1的個數

  3. BITPOS:找到第一個被設置為0或1的位置

BITPOS和BITCOUNT都可以接受位的地址范圍作為參數,這樣就不對對整個字符串做操作。下面是一個關于BITCOUNT的簡單例子:

> setbit key 0 1(integer) 0> setbit key 100 1(integer) 0> bitcount key(integer) 2

位圖的通常用法:

  • 各種實時分析

  • 存儲要求空間時間高效的與對象ID關聯的二進制信息。

假如你想知道你的網頁用戶中每天訪問最長的時間【6】,你從開始記錄天數,你把你的網頁公開化的第一天開始,計數為0,然后每當有用戶用戶網頁,使用SETBIT設置一位。位的下標可以簡單的認為是當前系統時間,減去第一天得到偏移,然后除以3600*24。 
使用這種方式,對于每一個用戶,你有一個包含每天訪問信息的字符串來表示。使用BITCOUNT命令可以得到某個用戶訪問網頁的天數。而使用多個BITOPs調用,可能簡單地獲取和分析位圖,就很容易地計算出longest streak。 
為了共享數據或避免對一個很大的鍵操作,bitmap可以分裂成多個鍵。要把一個位圖分裂成多個鍵而不是全部設置到一個鍵里面去,一個比較麻煩的方法就是讓每個鍵存儲M位,鍵名為鍵的數量/M,第N個位在這個鍵里的地址是數的位置%M。

HyperLogLogs

HyperLogLogs是一個概率性的數據結構,用于計算特別的東西(技術上常用于估算一個集的勢)。通過計算一個特別的表項需要使用相對于要計算的表項本身來說很大的內存,因為需要記住你已經見過的元素,以免重復計算。然后有一系列算法可以按精度使用內存:在redis的實現中,你最終得到一個標準錯誤的估計測量結果的可能性少于1%【7】。這個算法的神奇之處在于你再大需要相對于要計算的表項本身來說很大的內存空間,可能是只使用一個常數數量的空間。最壞情況下12K字節,如果元素少的話,這個空間會更小。 
Redis中的HLL,從技術上講,它是一個完全不同的數據結構,但像字符串一樣編碼,因此你可以使用GET來串行化一個HLL,使用SET并行到服務器。 
從概念上講,HLL的接口使用集來完成相同的工作。你會使用SADD把每一個觀測值寫入集中,使用SCARD來查詢集中的元素個數。因為SADD不會重復添加一個已存在的元素,因此集中的元素是唯一的。 
但是你不能把一個表項真正地添加入一個HLL,因為數據結構只包含并不真正存在的元素的狀態,API是一樣的:

  • 每當你看見一個新的元素,使用PFADD計數增加

  • 每當你想要恢復當前的近似值,使用PFCOUNT。【8】

> pfadd hll a b c d(integer) 1> pfcount hll(integer) 4

使用這種數據結構的一個例子統計在一個調整中用戶每天執行的請求數。 
Redis還可以對HLL執行求并集操作,請查詢完整文件獲取更多信息。

其它顯著的特性

關于redis的接口,還有其它一些重要的信息不能放在這個文檔中,但是非常值得引起你的注意:

  • 可以遞增地迭代鍵空間

  • 可以在服務器端運行LUA腳本獲取潛在因素和帶寬

  • redis還是一個發布-訂閱型服務器

REDIS所有的命令

<<ABOUT LIST>>

LPOP key :                    刪除并取得LIST頭部一個元素

RPOP key :                    刪除并取得LIST尾部一個元素

BLPOP key [key ...] timeout : 刪除并取得LIST頭部一個元素,如果沒有就BLOCK

BRPOP key [key ...] timeout : 刪除并取得LIST尾部一個元素,如果沒有就BLOCK

LPUSH key value :             在LIST頭部擴展一個元素

RPUSH key value :             在LIST尾部擴展一個元素

LPUSHX key value :            如果LIST存在,在LIST頭部擴展一個元素

RPUSHX key value :            如果LIST存在,在LIST尾部擴展一個元素

LINDEX key index :            通過INDEX取得LIST的一個元素

LLEN key :                    取得LIST的長度

LRANGE key start stop :       取得LIST在指定范圍內的元素

LREM key count value :        刪除LIST的元素們

LSET key index value :        設置LIST索引為INDEX的元素的值

LTRIM key start stop :        裁剪LIST,保留一定范圍的元素

RPOPLPUSH source destination :刪除當前LIST的尾部一個元素,并將其擴展到另一個LIST的尾部

BRPOPLPUSH source destination timeout :

                              彈出LIST一個元素,并將其插入到另一個LIST里,然后返回,如果前個LIST空就BLOCK

SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination] :

                              排序LIST,SET, SORTED SET

<<ABOUT SET>>

SADD key member :                       向SET中添加一個成員

SREM key member :                       從SET中刪除一個成員

SDIFF key [key ...] :                   集合求差集

SINTER key [key ...] :                  集合求交集

SUNION key [key ...] :                  集合求并集

SDIFFSTORE destination key [key ...] :  集合求差集,并保存結果集到另一集合

SINTERSTORE destination key [key ...] : 集合求交集,并保存結果集到另一集合

SUNIONSTORE destination key [key ...] : 集合求并集,并保存結果集到另一集合

SCARD key :                             取得SET成員總數

SISMEMBER key member :                  判斷給定值是否為SET成員

SPOP key :                              刪除并返回SET任一成員

SRANDMEMBER key :                       返回SET任一成員

SMEMBERS key :                          取得SET所有成員

SMOVE source destination member :       將一個SET中一個成員移動到另一個SET中

<<ABOUT SORTED SET>>

ZADD key score member :                 在SSET中添加一個成員,或者說更新已有成員的SCORE

ZCARD key :                             取得SSET的成員總數

ZCOUNT key min max :                    計算SSET中SCORE在一個給定范圍內的成員總數

ZINCRBY key :                           為SSET中的成員自增SCORE

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] :

                                        求SSET交集,并將結果集保存到一個新KEY

ZRANGE key start stop [WITHSCORES] :    返回SSET中一定INDEX范圍內的成員

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] : 返回SSET中一定SCORE范圍內的成員

ZREM key member :                       刪除SSET中一個成員

ZREMRANGEBYRANK key start stop :        刪除SSET一定INDEX范圍內的成員

ZREMRANGEBYSCORE key min max :          刪除SSET一定SCORE范圍內的成員

ZREVRANGE key start stop [WITHSCORES] : 返回SSET中一定INDEX范圍內的成員,其順序是SCORE從高到低

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] : 返回SSET中一定SCORE范圍內的成員,其順序是SCORE從高到低

ZSCORE key member :                     獲得SSET中與給定MEMBER關聯的SCORE

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] :

                                        SSET求并集,并將結果集存到一個新的KEY中

<<ABOUT HASH>>

HDEL key field :                            刪除一個HASHFIELD

HEXISTS key field :                         判斷一個HASHFIELD是否存在

HGET key field :                            獲得一個HASHFIELD的值

HGETALL key :                               獲得一個HASH所有的FIELDs和VALUEs

HINCRBY key field increment :               對HASHFIELD的整數值增加increment的整數值

HKEYS key :                                 獲得HASH所有的FIELD

HLEN key :                                  獲得HASH內FIELD總數

HMGET key field [field ...] :               獲得HASH指定FIELD的所有值

HMSET key field value [field value ...] :   設置HASH的一些FILED和VALUE

HSET key field value :                      設置HASH的某FIELD為某值

HSETNX key field value :                    當HASH的某FIELD不存在時候,設置其為某值

HVALS key :                                 獲得HASH的所有值

<<ABOUT KEY>>

DEL key [key ...] :         刪除一個KEY

GET key :                   獲得一個KEY的值

SETEX key seconds value :   設置KEY的VALUE和EXP時間

SETNX key value :           設置KEY的VALUE,前提是KEY之前不存在

SET key value :             設置KEY,VALUE

APPEND key value :          向一個KEY擴展一個值

DEBUG OBJECT key :          獲得一個KEY的DEBUG信息

DECR key :                  給一個KEY-1

DECRBY key integer :        給一個KEY-integer

EXISTS key :                判斷一個KEY是否存在

EXPIRE key seconds :        設定一個KEY的TTL(second)

EXPIREAT key timestamp :    設定一個KEY的TTL(unix timestamp)

TTL key :                   獲得KEY的TTL

PERSIST key :               刪除一個KEY的過期標志

KEYS pattern :              查找所有符合PATTERN的KEY

MOVE key db :               將一個KEY移動到另一個DATABASE中

RENAME key newkey :         重命名一個KEY

RENAMENX key newkey :       給一個KEY重命名,前提是新KEYNAME不存在

RANDOMKEY :                 從KEYSPACE返回一個任一的KEY

<<ABOUT VALUE>>

GETRANGE key start end :            獲得KEY對應的字符串里指定范圍的子串

GETSET key value :                  設置KEY對應的VALUE,并返回老的VALUE

INCR key :                          為KEY對應的整數值自增1

INCRBY key increment :              為KEY對應的整數值自增increment

MGET key [key ...] :                獲得所有指定KEY的值

MSET key value [key value ...] :    為指定的KEYS設置指定的VALUES

MSETNX key value [key value ...] :  當指定的KEY存在時候,為指定的KEYS設置指定的VALUES

STRLEN key :                        獲得KEY的VALUE長度

<<ABOUT SERVER>>

INFO :                                          獲得服務器的狀態信息和統計信息

MONITOR :                                       實時監聽SERVER獲得的所有請求

PING :                                          Ping服務器

QUIT :                                          關閉鏈接

PUBLISH channel message :                       發布一個消息到一個CHANNEL

AUTH password :                                 認證服務器

LASTSAVE :                                      獲得最后一次成功SAVETODISK的時間戳

OBJECT subcommand [arguments [arguments ...]] : 偵測REDIS對象的內部

PSUBSCRIBE pattern [pattern ...] :              監聽發布到CHANNEL的所有符合PATTERN的消息

PUNSUBSCRIBE [pattern [pattern ...]] :          停止監聽發布到CHANNEL的所有符合PATTERN的消息

CONFIG RESETSTAT :                              重設INFO命令返回的狀態信息

SUBSCRIBE channel [channel ...] :               監聽指定CHANNEL的消息

UNSUBSCRIBE [channel [channel ...]] :           停止監聽指定CHANNEL的消息

UNWATCH : Forget about all watched keys         停止監視所有被監視的KEY

WATCH key [key ...] :                           監視所有給定的KEY,來判斷MULTI和EXEC塊的執行

<<ABOUT DATABASE>>

SAVE Synchronously :    保存DATASET到硬盤

SELECT index :          切換當前數據庫

BGSAVE :                異步保存DATASET到硬盤

DBSIZE :                    返回一個DATABASE的KEY總數

FLUSHALL :                  刪除所有DATABASE上所有的KEY

FLUSHDB :                   刪除當前DATABASE上所有的KEY

SHUTDOWN Synchronously :                        保存DATASET到硬盤后,關閉服務器

<<CONFIGURE>>

CONFIG GET parameter :          獲得一個配置參數值

CONFIG SET parameter value :    設置一個配置參數為給定值

<<OTHER>>

GETBIT key offset :             返回KEY對應的VALUE在OFFSET的比特值

MULTI :                         標識一個業務塊的開始

SETRANGE key offset value :     從指定的OFFSET開始覆蓋寫KEY對應的VALUE串

BGREWRITEAOF :                  異步重寫append-only file

DEBUG SEGFAULT :                使服務器crash

DISCARD :                       忽略所有的以MULTI開頭的命令

ECHO message :                  ECHO message

EXEC :                          執行所有以MULTI開頭的命令

SLAVEOF host port :             使本服務器成為另一REDIS HOST的SLAVE,或者使本服務器成為主服務器

SYNC :                          內部備份命令

LINSERT key BEFORE|AFTER refvalue value : 向列表key的refvalue之前或者之后插入value

到此,相信大家對“redis數據結構有哪些內容”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

杭州市| 宽甸| 华阴市| 德保县| 嘉善县| 迁西县| 正镶白旗| 揭阳市| 龙南县| 无为县| 察哈| 霸州市| 芦山县| 海兴县| 永善县| 饶阳县| 丰镇市| 安阳县| 阳江市| 翼城县| 桓台县| 郓城县| 达日县| 鄂温| 霍城县| 丰原市| 溧水县| 大石桥市| 勃利县| 黄石市| 根河市| 家居| 安陆市| 闽清县| 高邑县| 靖远县| 富民县| 抚松县| 三亚市| 浙江省| 香格里拉县|