Redis數據類型和抽象介紹

 

Redis數據類型和抽象介紹

紅色不是平原鍵值存儲,它實際上是一個數據結構服務器支持不同類型的價值觀。這意味着,在傳統的鍵值存儲中,您將字符串鍵與字符串值相關聯,但在Redis中,值不僅限於一個簡單的字符串,還可以包含更復雜的數據結構。以下是Redis支持的所有數據結構的列表,本教程將分別討論這些結構:

  • 二進制安全字符串。
  • List:根據插入順序排序的字符串元素集合。他們基本上是鏈接列表.
  • SET:唯一的、未排序的字符串元素的集合。
  • 排序集,類似於集合,但每個字符串元素都與浮點數值相關聯,稱爲得分。元素總是按照它們的分數排序,所以不像集合一樣,可以檢索一系列元素(例如,您可能會問:給我前10位,或者最後10位)。
  • 散列,它是由與值關聯的字段組成的映射。字段和值都是字符串。這非常類似於Ruby或Python散列。
  • 位數組(或簡單的位圖):可以使用特殊命令來處理字符串值,如位數組:您可以設置和清除單個位,計數所有設置爲1的位,找到第一個集或未設置位,等等。
  • 超級Logs:這是一種概率數據結構,用於估計集合的基數。別害怕,這比看上去簡單.請參閱本教程的HyperLogLog部分後面的內容。
  • 流:僅附加提供抽象日誌數據類型的類似於映射的條目集合。它們被深埋在Redis流簡介.

瞭解這些數據類型是如何工作的,以及如何使用這些數據類型來解決給定的問題。命令引用因此,本文檔是關於Redis數據類型及其最常見模式的速成課程。

對於所有示例,我們將使用redis-cli實用工具,一個簡單但方便的命令行實用工具,用於向Redis服務器發出命令。

紅鍵

Redis鍵是二進制安全的,這意味着您可以使用任何二進制序列作爲鍵,從字符串“foo”到JPEG文件的內容。空字符串也是一個有效的鍵。

還有一些關於鑰匙的其他規則:

  • 很長的鑰匙不是個好主意。例如,一個1024字節的鍵不僅是內存方面的錯誤想法,還因爲在DataSet中查找鍵可能需要幾個昂貴的鍵比較。即使手頭的任務是匹配大值的存在,哈希(例如使用SHA 1)也是一個更好的主意,特別是從內存和帶寬的角度來看。
  • 很短的鍵往往不是個好主意。如果您可以編寫“user:1000:關注者”,那麼將“u1000flw”作爲鍵編寫是沒有什麼意義的。後者的可讀性更強,與鍵對象本身和Value對象使用的空間相比,添加的空間更小。雖然短鍵顯然會消耗更少的內存,但您的工作是找到合適的平衡。
  • 試着堅持模式。例如,“object-type:id”是個好主意,就像在“user:1000”中一樣。點或破折號常用於多詞字段,如“註釋:1234:回覆”或“註釋:1234:回覆-to”。
  • 允許的最大密鑰大小爲512 MB。

紅串

Redis字符串類型是可以與Redis鍵關聯的最簡單的值類型。它是memcached中唯一的數據類型,所以新手在Redis中使用它也是非常自然的。

因爲Redis鍵是字符串,所以當我們將字符串類型也用作值時,我們將字符串映射到另一個字符串。字符串數據類型對於許多用例非常有用,比如緩存HTML片段或頁面。

讓我們來玩一下字符串類型,使用redis-cli(所有示例將通過redis-cli在本教程中)。

> set mykey somevalue
OK
> get mykey
"somevalue"

如您所見,使用到達命令是我們設置和檢索字符串值的方式。請注意將替換已存儲到鍵中的任何現有值,即使鍵與非字符串值相關聯,如果鍵已經存在則也是如此。所以執行任務。

值可以是各種字符串(包括二進制數據),例如,您可以在值中存儲jpeg圖像。值不能大於512 MB。

這個命令有一些有趣的選項,這些選項作爲附加參數提供。例如,我可能會問如果鍵已經存在,則失敗,或者相反,只有當鍵已經存在時,它纔會成功:

> 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

這個英格爾命令將字符串值解析爲整數,將其遞增1,最後將獲得的值設置爲新值。還有其他類似的命令,如INCRBY德克爾DECRBY。在內部,它總是以一種稍微不同的方式執行相同的命令。

這意味着INGR是原子的嗎?即使是多個客戶端使用相同的密鑰發出incr,也永遠不會進入爭用狀態。例如,客戶端1讀取“10”,客戶端2同時讀取“10”,增量爲11,並將新值設置爲11。最終值始終爲12,讀取增量集操作將在所有其他客戶端不同時執行命令時執行。

有許多用於對字符串進行操作的命令。例如,GETSET命令設置一個新值的鍵,返回舊值作爲結果。例如,如果系統使用英格爾每次你的網站收到一個新的訪問者。您可能希望每小時收集一次此信息,而不會丟失一個增量。你可以的GETSET鍵,爲其分配“0”的新值,並返回舊值。

在單個命令中設置或檢索多個鍵的值的能力對於減少延遲也很有用。由於這個原因,有MSETMGET命令:

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

什麼時候MGET使用時,Redis將返回一個值數組。

更改和查詢密鑰空間

有些命令沒有在特定類型上定義,但對於與鍵空間進行交互很有用,因此,可以與任何類型的鍵一起使用。

例如,存在命令返回1或0以指示給定的鍵是否存在於數據庫中,而德爾命令刪除鍵和相關值,不管該值是什麼。

> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0

在這些例子中,您還可以看到德爾它本身返回1或0,這取決於鍵是否被移除(它是否存在)(沒有該名稱的密鑰)。

有許多與鍵空間相關的命令,但上述兩個命令與類型命令,該命令返回存儲在指定鍵中的值的類型:

> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none

紅寶石過期:生命時間有限的鑰匙

在繼續處理更復雜的數據結構之前,我們需要討論另一個功能,它可以不考慮值類型,並被稱爲紅寶石到期。基本上,您可以爲一個鍵設置一個超時,這是一個有限的生存時間。當存活時間流逝時,密鑰將自動銷燬,就像用戶調用德爾用鑰匙指揮。

關於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秒。在上面的示例中,我們使用了過期爲了設置過期(也可以使用它來設置另一個已具有過期的密鑰),如堅持可用於刪除過期並使密鑰永久持久)。但是,我們也可以使用其他Redis命令創建帶ExchangeWith的鍵。例如,使用備選方案:

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

上面的示例設置了一個具有字符串值的鍵。100有十秒的過期時間。後來TTL命令的調用,以檢查剩餘的時間來保存密鑰。

爲了設置和檢查過期時間(毫秒),請檢查PEXPIREPTTL命令和各種選擇。

紅寶石名單

要解釋列表數據類型,最好從一些理論開始,作爲術語列單信息技術人員經常以不適當的方式使用。例如,“Python列表”不是名稱所暗示的(鏈接列表),而是數組(實際上在Ruby中相同的數據類型稱爲Array)。

從一個非常普遍的角度來看,列表只是一個有序元素的序列:10,20,1,2,3是一個列表。但是,使用Array實現的列表的屬性與使用鏈表.

REDIS列表是通過鏈接列表實現的。這意味着,即使列表中有數以百萬計的元素,也會執行在列表的頭或尾中添加新元素的操作。恆定時間。控件添加新元素的速度。LPUSH命令指向一個包含10個元素的列表的頭,這與將一個元素添加到包含1000萬個元素的列表頭部相同。

缺點是什麼?訪問元素按指數在用Array(常數時間索引訪問)實現的列表中,速度非常快,而在由鏈接列表實現的列表中(在該列表中,操作需要與所訪問元素的索引成比例的工作量),速度不太快。

Redis列表是用鏈接列表實現的,因爲對於數據庫系統來說,能夠以非常快的方式將元素添加到非常長的列表中是至關重要的。另一個強大的優勢,就像您稍後會看到的,是Redis列表可以在恆定的時間內以恆定的長度獲取。

當快速訪問大型元素集合的中部非常重要時,可以使用不同的數據結構,稱爲排序集。排序集將在本教程後面討論。

使用Redis列表的第一步

這個LPUSH命令將一個新元素添加到列表的左邊(頭部),而RPUSH命令在右邊(尾部)的列表中添加一個新元素。最後朗格命令從列表中提取元素的範圍:

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

請注意朗格接受兩個索引,即要返回的範圍的第一個和最後一個元素。這兩個索引都可以是負的,告訴Redis從末尾開始計數:so-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列表上定義的一個重要操作是POP元素。彈出元素是同時從列表中檢索元素和從列表中刪除元素的操作。您可以從左邊和右邊彈出元素,類似於如何在列表的兩邊推送元素:

> rpush mylist a b c
(integer) 3
> rpop mylist
"c"
> rpop mylist
"b"
> rpop mylist
"a"

我們添加了三個元素並彈出了三個元素,因此在這個命令序列的末尾,列表是空的,沒有更多的元素可以彈出。如果我們嘗試彈出另一個元素,這就是我們得到的結果:

> rpop mylist
(nil)

redis返回一個空值,以指示列表中沒有元素。

列表的通用用例

列表對於許多任務很有用,兩個非常有代表性的用例如下:

  • 記住用戶在社交網絡上發佈的最新更新。
  • 進程之間的通信,使用使用者-生產者模式(生產者將項目推入列表)和使用者(通常是工人)使用這些項並執行操作。Redis有特殊的列表命令來使這個用例更加可靠和高效。

例如,兩個流行的Ruby庫雷克塞德基克使用隱藏項下的Redis列表來實現後臺作業。

流行的Twitter社交網絡獲取最新的推特由用戶發佈到Redis列表。

爲了一步一步地描述一個常見的用例,假設您的主頁顯示了在照片共享社交網絡中發佈的最新照片,並且希望加快訪問速度。

  • 每次用戶發佈新照片時,我們都會將其ID添加到以下列表中LPUSH.
  • 當用戶訪問主頁時,我們使用LRANGE 0 9爲了得到最新的10條貼出的物品。

上限列表

在許多用例中,我們只想使用列表來存儲最新項目,不管它們是什麼:社交網絡更新、日誌或其他任何東西。

Redis允許我們使用列表作爲有上限的集合,只需要記住最新的N項,並使用LTRIM命令。

這個LTRIM命令類似於朗格,但是而不是顯示指定的元素範圍。它將此範圍設置爲新的列表值。在給定範圍之外的所有元素都被移除。

舉一個例子可以更清楚地說明:

> 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的列表元素,其他所有內容都將被丟棄。這允許一種非常簡單但有用的模式:執行列表推送操作+將列表修剪操作放在一起,以便添加新元素並丟棄超過限制的元素:

LPUSH mylist <some element>
LTRIM mylist 0 999

上面的組合添加了一個新元素,並且只接受列表中的1000個最新元素。帶着朗格您可以訪問頂部的項目,而不需要記住非常老的數據。

注:同時朗格在技術上是O(N)命令,訪問指向列表的頭部或尾部的小範圍是一個恆定的時間操作。

阻止列表上的操作

列表有一個特殊的特性,使它們適合實現隊列,並且通常作爲進程間通信系統的一個構建塊:阻塞操作。

假設您希望使用一個進程將項目推入列表中,並使用不同的流程來實際處理這些項。這是通常的生產者/消費者設置,可以通過以下簡單方式實現:

  • 要將項目推入列表,生產者將調用LPUSH.
  • 要從列表中提取/處理項,使用者將調用RPOP.

但是,有時列表可能是空的,沒有什麼可處理的,所以RPOP只返回NULL。在這種情況下,消費者被迫等待一段時間,然後再用RPOP。這叫做輪詢,在這種情況下不是一個好主意,因爲它有幾個缺點:

  1. 強制Redis和客戶端處理無用的命令(當列表爲空時,所有請求都不會完成實際的工作,它們只會返回NULL)。
  2. 爲項目的處理添加延遲,因爲在工作人員收到NULL後,它會等待一段時間。爲了使延遲更小,我們可以減少呼叫之間的等待時間。RPOP,具有放大問題1的效果,即對Redis的更多無用調用。

因此Redis實現了名爲BRPOPBLPOP的版本RPOPLPOP如果列表爲空,則可以阻塞:只有在向列表中添加新元素或達到用戶指定的超時時,它們纔會返回給調用方。

這是一個例子BRPOP我們可以給工人打電話:

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

它的意思是:“等待列表中的元素。tasks,但如果5秒後沒有可用的元素,則返回“。

注意,您可以使用0作爲超時來永遠等待元素,還可以指定多個列表,而不僅僅是一個列表,以便同時等待多個列表,並在第一個列表收到元素時得到通知。

有幾件事要注意BRPOP:

  1. 客戶端以有序的方式服務:阻止等待列表的第一個客戶端,在某個元素被其他客戶端推送時首先服務,依此類推。
  2. 返回值與RPOP它是一個雙元素數組,因爲它還包括鍵的名稱,因爲BRPOPBLPOP能夠阻止從多個列表中等待元素。
  3. 如果到達超時,則返回NULL。

關於列表和阻塞操作,您應該瞭解更多的事情。我們建議您多閱讀以下內容:

  • 可以使用以下方法構建更安全的隊列或旋轉隊列RPOPLPUSH.
  • 還有一個命令的阻塞變體,稱爲BRPOPLPUSH.

自動創建和移除鍵

到目前爲止,在我們的示例中,我們不必在推送元素之前創建空列表,也不必在元素中不再有元素時刪除空列表。當列表保持爲空時,Redis有責任刪除鍵,或者在鍵不存在的情況下創建一個空列表,並且我們試圖向其中添加元素,例如,使用LPUSH.

這並不限於列表,它適用於由多個元素組成的所有Redis數據類型--流、集、排序集和散列。

基本上,我們可以用三個規則來總結行爲:

  1. 當我們向聚合數據類型添加元素時,如果目標鍵不存在,則在添加元素之前創建一個空聚合數據類型。
  2. 當我們從聚合數據類型中刪除元素時,如果該值保持爲空,則該鍵將自動銷燬。Stream數據類型是此規則的唯一例外。
  3. 調用只讀命令,如伊倫(返回列表的長度),或使用空鍵刪除元素的寫命令總是產生相同的結果,就像該鍵持有命令希望查找的類型的空聚合類型一樣。

規則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散列看起來就像人們所期望的“散列”(散列),其中包含字段值對:

> 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設置散列的多個字段,同時赫格檢索單個字段。HMGET類似於赫格但是返回一個值數組:

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

有些命令也可以對單個字段執行操作,如辛尼:

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

你可以找到文檔中哈希命令的完整列表.

值得注意的是,小散列(即具有小值的幾個元素)在內存中以特殊方式編碼,從而使它們具有非常高的內存效率。

Redis集

redis集是字符串的無序集合。這個賽德命令向集合添加新元素。還可以對集合執行許多其他操作,比如測試給定元素是否已經存在,執行多個集合之間的交叉、合併或差異等等。

> 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”則不是。

集合很好地表達了對象之間的關係。例如,我們可以很容易地使用SET來實現標記。

對這個問題建模的一個簡單方法是爲我們想要標記的每個對象設置一個集合。集合包含與對象關聯的標記的ID。

一個例子是在新聞文章上加上標籤。如果使用標記1、2、5和77標記文章ID 1000,則集合可以將這些標記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 tag:1:news tag:2:news tag:10:news tag:27:news
... results here ...

除了交集之外,您還可以執行聯合、差分、提取一個隨機元素,等等。

提取元素的命令被調用SPOP,並且可以方便地模擬某些問題。例如,爲了實現基於網絡的撲克遊戲,您可能需要用一組集合來表示您的牌盤。假設我們使用一個字符前綴來表示(C)Lubs,(D)IAMES,(H)EATS,(S)PADES:

>  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 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 game:1:deck
(integer) 47

數學計算:52-5=47.

當您只需要獲取隨機元素而不將它們從集合中移除時,斯蘭德梅爾命令適合該任務。它還具有返回重複和非重複元素的能力。

Redis排序集

排序集是一種數據類型,類似於集合和散列之間的混合。與集合一樣,排序集是由唯一的、不重複的字符串元素組成的,因此在某種意義上,排序集也是一個集合。

但是,雖然集合中的元素沒有排序,但排序集中的每個元素都與一個浮點值相關聯,稱爲得分(這就是爲什麼類型也類似於哈希,因爲每個元素都映射到一個值)。

此外,排序集中的元素包括井然有序(因此它們不是根據請求排序的,Order是用於表示排序集的數據結構的一個特性)。它們是根據下列規則訂購的:

  • 如果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

如你所見ZADD類似於賽德,但需要附加一個參數(放在要添加的元素之前),即得分。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在這裏工作,就像在朗格指揮)。

如果我想以相反的方式訂購它們,從小到老呢?使用雷夫朗格(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"

按範圍操作

排序集比這更強大。他們可以在靶場上操作。讓我們把所有出生到1950年的人都包括在內。我們使用茲朗貝斯克命令:

> 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秩操作。可以詢問元素在有序元素集合中的位置。

> zrank hackers "Anita Borg"
(integer) 4

這個ZREVRANK命令也可用,以獲得排序,考慮元素排序的降序方式。

詞典學分數

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

範圍可以是包含的或獨佔的(取決於第一個字符),也可以使用+-絃樂。有關更多信息,請參見文檔。

這個特性很重要,因爲它允許我們使用排序集作爲通用索引。例如,如果要用128位無符號整數參數對元素進行索引,則只需將元素添加到具有相同分數(例如0)的排序集中,但要使用由16字節前綴組成的大端128位數。由於大端字節中的數字(按原始字節順序排序)實際上也是按數字順序排列的,所以您可以在128位空間中請求範圍,並獲得元素的值丟棄前綴。

如果您想在更嚴肅的演示的上下文中查看該特性,請檢查Redis自動完成演示.

更新評分:領導委員會

在切換到下一個主題之前,只需對排序集做最後的說明。排序集的分數可以隨時更新。只是打電話ZADD針對已包含在排序集中的元素,將使用O(log(N))時間複雜性。因此,當有大量更新時,排序集是合適的。

由於這一特點,一個常見的用例是領導委員會。典型的應用程序是一款facebook遊戲,在遊戲中,你結合了將用戶按高分排序的能力,再加上獲取排名操作,以顯示排名前N的用戶,以及在領導委員會中的用戶排名(例如,“您是這裏的#4932最佳得分”)。

位圖

位圖不是實際的數據類型,而是定義在字符串類型上的一組面向位的操作。由於字符串是二進制安全塊,其最大長度爲512 MB,因此它們適合設置爲2。32不同的部分。

比特操作分爲兩組:固定時間的單比特操作,如將位設置爲1或0,或獲取其值,以及對比特組的操作,例如,計算給定比特範圍內的集合位數(例如,人口計數)。

位圖的最大優點之一是,它們在存儲信息時往往節省了極大的空間。例如,在使用增量用戶ID表示不同用戶的系統中,只需使用512 MB內存就可以記住單個比特信息(例如,知道用戶是否想接收時事通訊)。

位設置並使用SETBITGETBIT命令:

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

這個SETBIT命令的第一個參數是位數,第二個參數是要將位設置爲1或0的值。如果尋址位在當前字符串長度之外,則該命令會自動擴大字符串。

GETBIT只返回指定索引處位的值。超出範圍的位(尋址位於存儲在目標鍵中的字符串長度之外的位)總是被認爲是零。

在一組位上有三個操作命令:

  1. BITOP執行不同字符串之間的逐位操作。提供的操作是AND、OR、XOR和NOT。
  2. BITCOUNT執行人口計數,報告設置爲1的位數。
  3. Bitpos查找指定值爲0或1的第一個位。

雙管齊下BitposBITCOUNT可以使用字符串的字節範圍進行操作,而不是運行字符串的整個長度。下面是一個簡單的例子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.

超級Logs

HyperLoglog是一種用於計數唯一事物的概率數據結構(從技術上講,這是指估計集合的基數)。通常,計算唯一項目需要使用與要計數的項目數量成比例的內存量,因爲您需要記住您在過去見過的元素,以避免多次計算它們。然而,有一組算法可以用內存來換取精度:以一個標準錯誤的估計度量結束,在Redis實現的情況下,這個誤差小於1%。這個算法的神奇之處在於,您不再需要使用與計數項的數量成比例的內存量,而是可以使用常量的內存!在最壞的情況下,可以使用12k字節,如果您的HyperLoglog(我們從現在起只稱它們爲HLL)所見的元素非常少,則會少得多。

Redis中的hls雖然在技術上是一種不同的數據結構,但被編碼爲Redis字符串,因此您可以調用到達序列化HLL,以及將其反序列化回服務器。

從概念上講,HLL API就像使用SET來執行相同的任務一樣。你會賽德將每一個觀察到的元素放入一個集合,並使用浮渣檢查集合內的元素數,這些元素是唯一的,因爲賽德不會重新添加現有元素。

而你不是真的添加項目由於數據結構只包含不包含實際元素的狀態,因此API是相同的:

  • 每次看到新元素時,都會將其添加到PFADD.
  • 每次要檢索唯一元素的當前近似值時,帶着PFADD到目前爲止,您使用的是PFCOUNT.

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

這種數據結構的用例是計算用戶每天在搜索表單中執行的唯一查詢。

Redis也可以執行Hlls的聯合,請檢查完整文件想了解更多信息。

其他顯著特徵

Redis API中還有其他一些重要的東西不能在本文檔的上下文中進行探討,但值得您注意:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章