《Redis入門指南(第二版)》讀書思考總結之Redis五大數據類型

熱身:系統級命令redis

1. 得到符合規則的鍵名列表數據庫

KEYS pattern

     模式匹配數組

    產品的緩存:product+"."+....;  => keys product*緩存

    訂單的緩存:order+"."+...;    => keys order*服務器

使用 KEYS *能得到Redis中的全部鍵函數

提示:KEYS命令須要遍歷Redis中的全部鍵,當鍵的數量較多時會影響性能,不建議在生產環境中使用。Redis不區分命令大小寫。post

 

2. 判斷一個鍵是否存在性能

EXISTS key 

若是鍵存在則返回整數類型1,不然返回0。學習

3. 刪除鍵 測試

DEL key [key …]

能夠刪除一個或多個鍵,返回值是刪除的鍵的個數。

4. 得到鍵值的數據類型

 TYPE key

5.清空數據庫

Flushdb

6.過時時間

Expire(秒爲單位)

  若是要作緩存,那麼必定要有一個過時時間。

7.查看剩餘存活時間。

ttl 查看key還有多長存活時間。(秒爲單位)

 

  爲了讓你更全面地瞭解 Redis的每種數據類型,接下來我會先講解如何將Redis做爲數據庫使用,可是實際上 Redis可不僅是數據庫這麼簡單,更多的公司和團隊將 Redis用做緩存和隊列系統,而這部份內容等你掌握了Redis的基礎後我會再進行介紹,下面將介紹redis的五大數據類型,並經過實戰一個博客管理系統的原理來說解他們的應用。

1、字符串類型

1. 介紹

  字符串類型是 Redis 中最基本的數據類型,它能存儲任何形式的字符串,包括二進制數據。你能夠用其存儲用戶的郵箱、JSON 化的對象甚至是一張圖片。一個字符串類型鍵容許存儲的數據的最大容量是512 MB。

  字符串類型是其餘4種數據類型的基礎,其餘數據類型和字符串類型的差異從某種角度來講只是組織字符串的形式不一樣。例如,列表類型是以列表的形式組織字符串,而集合類型是以集合的形式組織字符串。

2. 命令

(1)賦值與取值

SET key value

GET key

  key等於」hello」在Redis中是這樣表示的:

redis> SET key hello

OK

  想要讀取鍵值則更簡單:

redis> GET key

"hello"

  當鍵不存在時會返回空結果。

(2) 遞增數字

INCR key

  前面說過字符串類型能夠存儲任何形式的字符串,當存儲的字符串是整數形式時, Redis 提供了一個實用的命令 INCR,其做用是讓當前鍵值遞增,並返回遞增後的值,用法爲:

redis> INCR num

(integer) 1

redis> INCR num

(integer) 2

  當要操做的鍵不存在時會默認鍵值爲0,因此第一次遞增後的結果是1。當鍵值不是整數時Redis會提示錯誤。

  包括 INCR在內的全部Redis命令都是原子操做(atomic operation)的。

  原子操做取「原子」的「不可拆分」的意思,原子操做是最小的執行單位,不會在執行的過程當中被其餘命令插入打斷。

3. 實戰應用

(1) 博客文章訪問量統計

咱們能夠爲每篇文章使用一個名爲post:文章ID:page.view的鍵來記錄文章的訪問量,每次訪問文章的時候使用INCR命令使相應的鍵值遞增。

Redis 對於鍵的命名並無強制的要求,但比較好的實踐是用「對象類型:對象ID:對象屬性」來命名一個鍵,如使用鍵user:1:friends來存儲ID爲1的用戶的好友列表。對於多個單詞則推薦使用「.」分隔。

(2)生成自增ID

Redis中的實現方法:對於每一類對象使用名爲對象類型(複數形式):count的鍵(如users:count)來存儲當前類型對象的數量,每增長一個新對象時都使用INCR命令遞增該鍵的值。因爲使用INCR命令創建的鍵的初始鍵值是1,因此能夠很容易得知, INCR命令的返回值既是加入該對象後的當前類型的對象總數,又是該新增對象的ID。

(3)存儲文章數據

因爲每一個字符串類型鍵只能存儲一個字符串,而一篇博客文章是由標題、正文、做者與發佈時間等多個元素構成的。爲了存儲這些元素,咱們須要使用序列化函數(如PHP中的 serialize和JavaScript中的 JSON.stringify)將它們轉換成一個字符串。除此以外由於字符串類型鍵能夠存儲二進制數據,因此也可使用MessagePack進行序列化,速度更快,佔用空間也更小。

4. 其餘命令

(1)增長指定的整數

INCRBY key increment

INCRBY命令與INCR命令基本同樣,只不過前者能夠經過increment參數指定一次增長的數值,如:

redis> INCRBY bar 2

(integer) 2

redis> INCRBY bar 3

(integer) 5

(2)減小指定的整數

DECR key DECRBY key decrement

  DECR命令與INCR命令用法相同,只不過是讓鍵值遞減,例如:

redis> DECR bar

(integer) 4

(3)增長指定浮點數

INCRBYFLOAT key increment

  INCRBYFLOAT命令相似INCRBY命令,差異是前者能夠遞增一個雙精度浮點數,如:

redis> INCRBYFLOAT bar 2.7

"6.7"

redis> INCRBYFLOAT bar 5E+4

"50006.69999999999999929"

(4)向尾部追加值

APPEND key value

APPEND做用是向鍵值的末尾追加value。若是鍵不存在則將該鍵的值設置爲value,即至關於 SET key value。返回值是追加後字符串的總長度。

如:

redis> SET key hello

OK

redis> APPEND key " world!"

(integer) 12

此時 key 的值是"hello world!"。

APPEND 命令的第二個參數加了雙引號,緣由是該參數包含空格,在redis-cli中輸入須要雙引號以示區分。

(5)獲取字符串長度

STRLEN key

STRLEN命令返回鍵值的長度,若是鍵不存在則返回0。

例如:

redis> STRLEN key

(integer) 12

redis> SET key 你好

OK

redis> STRLEN key

(integer) 6

  字符串類型能夠存儲二進制數據,因此它能夠存儲任何編碼的字符串。例子中Redis接收到的是使用UTF-8編碼的中文,因爲「你」和「好」兩個字的UTF-8編碼的長度都是3,因此此例中會返回6。

(6)同時得到/設置多個鍵值

MGET key [key …]

MSET key value [key value …]

MGET/MSET 與GET/SET 類似,不過MGET/MSET 能夠同時得到/設置多個鍵的鍵值。

例如:

redis> MSET key1 v1 key2 v2 key3 v3

OK

redis> GET key2

"v2"

redis> MGET key1 key3

1) "v1"

2) "v3"

(7)位操做

GETBIT key offset

SETBIT key offset value

BITCOUNT key [start] [end]

BITOP operation destkey key [key …]

一個字節由8個二進制位組成,Redis提供了4個命令能夠直接對二進制位進行操做。

1)GETBIT命令能夠得到一個字符串類型鍵指定位置的二進制位的值(0或1),索引從0開始,若是須要獲取的二進制位的索引超出了鍵值的二進制位的實際長度則默認位值是0。

2)SETBIT 命令能夠設置字符串類型鍵指定位置的二進制位的值,返回值是該位置的舊值。

3)BITCOUNT命令能夠得到字符串類型鍵中值是1的二進制位個數。

4)BITOP命令能夠對多個字符串類型鍵進行位運算,並將結果存儲在destkey參數指定的鍵中。BITOP命令支持的運算操做有AND、OR、XOR和NOT。

5)Redis 2.8.7引入了 BITPOS命令,能夠得到指定鍵的第一個位值是0或者1的位置。

若是不設置結束字節且鍵值的全部二進制位都是1,則當要查詢值爲0的二進制位偏移量時,返回結果會是鍵值長度的下一個字位的偏移量。這是由於 Redis 會認爲鍵值長度以後的二進制位都是0。

(7)位操做應用舉例

利用位操做命令能夠很是緊湊地存儲布爾值。好比若是網站的每一個用戶都有一個遞增的整數ID,若是使用一個字符串類型鍵配合位操做來記錄每一個用戶的性別(用戶ID做爲索引,二進制位值1和0表示男性和女性),那麼記錄100萬個用戶的性別只需佔用100 KB多的空間,並且因爲GETBIT和SETBIT的時間複雜度都是O(1),因此讀取二進制位值性能很高。

使用 SETBIT 命令時,若是當前鍵的鍵值長度小於要設置的二進制位的偏移量時,Redis會自動分配內存並將鍵值的當前長度到指定的偏移量之間的二進制位都設置爲0。若是要分配的內存過大,則極可能會形成服務器的暫時阻塞而沒法接收同一時間的其餘請求。

仍是舉剛纔存儲網站用戶性別的例子,若是這個網站的用戶ID是從100000001開始的,那麼會形成10多MB的浪費,正確的作法是給每一個用戶的ID減去100000000再進行存儲。

2、散列類型

1. 介紹

 

 

  咱們如今已經知道 Redis 是採用字典結構以鍵值對的形式存儲數據的,而散列類型(hash)的鍵值也是一種字典結構,其存儲了字段(field)和字段值的映射,但字段值只能是字符串,不支持其餘數據類型,換句話說,散列類型不能嵌套其餘的數據類型。一個散列類型鍵能夠包含至多2^32−1個字段。

  除了散列類型,Redis 的其餘數據類型一樣不支持數據類型嵌套。好比集合類型的每一個元素都只能是字符串,不能是另外一個集合或散列表等。

  散列類型適合存儲對象:使用對象類別和 ID 構成鍵名,使用字段表示對象的屬性,而字段值則存儲屬性值。例如要存儲ID爲2的汽車對象,能夠分別使用名爲color、name和price的3個字段來存儲該輛汽車的顏色、名稱和價格。

 

 

  回想關係數據庫中存儲汽車對象:

 

 

  增長一個屬性後對於ID爲2和3的兩條字段而言data字段是冗餘的。

  Redis 的散列類型則不存在這個問題。雖然咱們在圖 3-5 中描述了汽車對象的存儲結構,可是這個結構只是人爲的約定,Redis並不要求每一個鍵都依據此結構存儲,咱們徹底能夠自由地爲任何鍵增減字段而不影響其餘鍵。

2. 命令

(1)HSET命令用來給字段賦值,而HGET命令用來得到字段的值。

  HSET 命令的方便之處在於不區分插入和更新操做,這意味着修改數據時不用事先判斷字段是否存在來決定要執行的是插入操做(update)仍是更新操做(insert)。當執行的是插入操做時(即以前字段不存在)HSET命令會返回1,當執行的是更新操做時(即以前字段已經存在)HSET命令會返回0。更進一步,當鍵自己不存在時,HSET命令還會自動創建它。

  須要同時設置多個字段的值時,可使用HMSET命令。

  Redis中每一個鍵都屬於一個明確的數據類型,如經過 HSET命令創建的鍵是散列類型,經過SET命令創建的鍵是字符串類型等等。使用一種數據類型的命令操做另外一種數據類型的鍵會提示錯誤:"ERR Operation against a key holding the wrong kind of value"。

  若是想獲取鍵中全部字段和字段值殊不知道鍵中有哪些字段時應該使用HGETALL命令。如:

redis> HGETALL car

1) "price"

2) "500"

3) "name"

4) "BMW"

(2)判斷字段是否存在

 HEXISTS key field

  HEXISTS命令用來判斷一個字段是否存在。若是存在則返回1,不然返回0(若是鍵不存在也會返回0)。

(3)當字段不存在時賦值

HSETNX key field value

HSETNX命令與HSET命令相似,區別在於若是字段已經存在,HSETNX命令將不執行任何操做。

(4)增長指定數字

HINCRBY key field increment

(5)刪除字段

HDEL key field [field …]

HDEL命令能夠刪除一個或多個字段,返回值是被刪除的字段個數:

redis> HDEL car price

(integer) 1

redis> HDEL car price

(integer) 0

3. 實戰應用

(1)存儲文章數據

 

  可使用 HGETALL 命令得到一個對象的全部字段,刪除一個對象時只須要刪除一個鍵,另外存儲一樣的數據散列類型每每比字符串類型更加節約空間。

(2)存儲文章縮略名

  每一個文章的縮略名必須是惟一的,因此在發佈文章時程序須要驗證用戶輸入的縮略名是否存在,同時也須要經過縮略名得到文章的ID。

  咱們可使用一個散列類型的鍵slug.to.id來存儲文章縮略名和ID之間的映射關係。其中字段用來記錄縮略名,字段值用來記錄縮略名對應的ID。這樣就可使用HEXISTS命令來判斷縮略名是否存在,使用HGET命令來得到縮略名對應的文章ID了。

4. 其餘命令

(1)只獲取字段名或字段值

HKEYS key

HVALS key

(2)得到字段數量

HLEN key

例如:

redis> HLEN car

(integer) 2

3、列表類型

1. 介紹

  列表類型(list)能夠存儲一個有序的字符串列表,經常使用的操做是向列表兩端添加元素,或者得到列表的某一個片斷。

  列表類型內部是使用雙向鏈表(double linked list)實現的,因此向列表兩端添加元素的時間複雜度爲O(1),獲取越接近兩端的元素速度就越快。這意味着即便是一個有幾千萬個元素的列表,獲取頭部或尾部的10條記錄也是極快的(和從只有20個元素的列表中獲取頭部或尾部的10條記錄的速度是同樣的),不過使用鏈表的代價是經過索引訪問元素比較慢。

  這種特性使列表類型能很是快速地完成關係數據庫難以應付的場景:

  如社交網站的新鮮事,咱們關心的只是最新的內容,使用列表類型存儲,即便新鮮事的總數達到幾千萬個,獲取其中最新的100條數據也是極快的。一樣由於在兩端插入記錄的時間複雜度是O(1),列表類型也適合用來記錄日誌,能夠保證加入新日誌的速度不會受到已有日誌數量的影響。

  與散列類型鍵最多能容納的字段數量相同,一個列表類型鍵最多能容納2^32−1個元素。

2.命令

(1)向列表兩端增長元素

 LPUSH key value [value …]

 RPUSH key value [value …]

LPUSH命令用來向列表左邊增長元素,返回值表示增長元素後列表的長度。

redis> LPUSH numbers 1

(integer) 1

LPUSH命令還支持同時增長多個元素,例如:

redis> LPUSH numbers 2 3

(integer) 3

LPUSH會先向列表左邊加入"2",而後再加入"3",因此此時numbers鍵中的數據如圖3-9所示。

向列表右邊增長元素的話則使用RPUSH命令。

(2)從列表兩端彈出元素

LPOP key

RPOP key

有進有出,LPOP命令能夠從列表左邊彈出一個元素。LPOP命令執行兩步操做:第一步是將列表左邊的元素從列表中移除,第二步是返回被移除的元素值。

例如,從 numbers列表左邊彈出一個元素(也就是"3"):

redis> LPOP numbers

"3"

RPOP命令能夠從列表右邊彈出一個元素。

  結合上面提到的 4 個命令可使用列表類型來模擬棧和隊列的操做:若是想把列表當作棧,則搭配使用LPUSH和LPOP或RPUSH和RPOP,若是想當成隊列,則搭配使用LPUSH和RPOP或RPUSH和LPOP。

(3)獲取列表中元素的個數

 LLEN key

當鍵不存在時LLEN會返回0:

redis> LLEN numbers

(integer) 3

  LLEN 命令的功能相似SQL語句 SELECT COUNT(*) FROM table_name,可是 LLEN的時間複雜度爲O(1),使用時Redis會直接讀取現成的值,而不須要像部分關係數據庫(如使用InnoDB存儲引擎的MySQL表)那樣須要遍歷一遍數據表來統計條目數量。

(4)得到列表片斷

LRANGE key start stop

 

  LRANGE命令是列表類型最經常使用的命令之一,它可以得到列表中的某一片斷。LRANGE命令將返回索引從 start到 stop之間的全部元素(包含兩端的元素)。與大多數人的直覺相同,Redis的列表起始索引爲0。

  LRANGE命令也支持負索引,表示從右邊開始計算序數,如"−1"表示最右邊第一個元素,"-2"表示最右邊第二個元素,依次類推。

顯然,LRANGE numbers 0 -1 能夠獲取列表中的全部元素。

另一些特殊狀況以下:

1)若是start的索引位置比stop的索引位置靠後,則會返回空列表。

2)若是stop大於實際的索引範圍,則會返回到列表最右邊的元素。

(5)刪除列表中指定的值

LREM key count value

LREM命令會刪除列表中前count個值爲value的元素,返回值是實際刪除的元素個數。根據count值的不一樣,LREM命令的執行方式會略有差別。

1)當 count > 0時 LREM 命令會從列表左邊開始刪除前 count 個值爲 value的元素。

2)當 count < 0時 LREM 命令會從列表右邊開始刪除前|count|個值爲 value 的元素。  

3)當 count = 0是 LREM命令會刪除全部值爲 value的元素。

3. 實戰應用

(1)存儲文章ID列表

咱們使用列表類型鍵posts:list記錄文章ID列表。當發佈新文章時使用LPUSH命令把新文章的ID加入這個列表中,另外刪除文章時也要記得把列表中的文章ID 刪除,就像這樣:

LREM posts:list 1 要刪除的文章的ID

有了文章 ID列表,就可使用 LRANGE命令來實現文章的分頁顯示了。

(2)存儲評論列表

咱們能夠將一條評論的各個元素序列化成字符串後做爲列表類型鍵中的元素來存儲。使用列表類型鍵post:文章的ID:comments來存儲某個文章的全部評論。

發佈評論的僞代碼以下(以ID爲42的文章爲例):

#將評論序列化成字符串

$serializedComment = serialize($author, $email, $time, $content)

LPUSH post:42:comments, $serializedComment

讀取評論時一樣使用LRANGE命令便可。

4.其餘命令

(1)得到/設置指定索引的元素值

LINDEX key index

LSET key index value

  若是要將列表類型看成數組來用,LINDEX命令是必不可少的。LINDEX命令用來返回指定索引的元素,索引從0開始。

  LSET是另外一個經過索引操做列表的命令,它會將索引爲index的元素賦值爲value。

例如:

redis> LSET numbers 1 7

OK

redis> LINDEX numbers 1

"7"

(2)只保留列表指定片斷

  LTRIM key start end LTRIM 命令能夠刪除指定索引範圍以外的全部元素,其指定列表範圍的方法和LRANGE命令相同。

  LTRIM命令常和LPUSH命令一塊兒使用來限制列表中元素的數量,好比記錄日誌時咱們但願只保留最近的100條日誌,則每次加入新元素時調用一次LTRIM命令便可:

LPUSH logs $newLog

LTRIM logs 0 99

(3)向列表中插入元素

LINSERT key BEFORE|AFTER pivot value

 

  LINSERT 命令首先會在列表中從左到右查找值爲 pivot 的元素,而後根據第二個參數是BEFORE仍是AFTER來決定將value插入到該元素的前面仍是後面。

  LINSERT命令的返回值是插入後列表的元素個數。

(4)將元素從一個列表轉到另外一個列表

RPOPLPUSH source destination

  RPOPLPUSH是個頗有意思的命令,從名字就能夠看出它的功能:先執行RPOP命令再執行LPUSH命令。RPOPLPUSH命令會先從source列表類型鍵的右邊彈出一個元素,而後將其加入到destination列表類型鍵的左邊,並返回這個元素的值,整個過程是原子的。

  當把列表類型做爲隊列使用時,RPOPLPUSH 命令能夠很直觀地在多個隊列中傳遞數據。當source和destination相同時,RPOPLPUSH命令會不斷地將隊尾的元素移到隊首,藉助這個特性咱們能夠實現一個網站監控系統:

  使用一個隊列存儲須要監控的網址,而後監控程序不斷地使用 RPOPLPUSH 命令循環取出一個網址來測試可用性。這裏使用RPOPLPUSH命令的好處在於在程序執行過程當中仍然能夠不斷地向網址列表中加入新網址,並且整個系統容易擴展,容許多個客戶端同時處理隊列。

4、集合類型

1.介紹

  集合的概念高中的數學課就學習過。在集合中的每一個元素都是不一樣的,且沒有順序。一個集合類型(set)鍵能夠存儲至多2^32 −1個(相信這個數字對你們來講已經很熟悉了)字符串。

  集合類型的經常使用操做是向集合中加入或刪除元素、判斷某個元素是否存在等,因爲集合類型在Redis內部是使用值爲空的散列表(hash table)實現的,因此這些操做的時間複雜度都是O(1)。最方便的是多個集合類型鍵之間還能夠進行並集、交集和差集運算,稍後就會看到靈活運用這一特性帶來的便利。

2.命令

(1)增長/刪除元素

SADD key member [member …]

SREM key member [member …]

SADD 命令用來向集合中增長一個或多個元素,若是鍵不存在則會自動建立。由於在一個集合中不能有相同的元素,因此若是要加入的元素已經存在於集合中就會忽略這個元素。本命令的返回值是成功加入的元素數量(忽略的元素不計算在內)。

SREM命令用來從集合中刪除一個或多個元素,並返回刪除成功的個數。

(2)得到集合中的全部元素

SMEMBERS key

SMEMBERS命令會返回集合中的全部元素。

(3)判斷元素是否在集合中

 SISMEMBER key member

判斷一個元素是否在集合中是一個時間複雜度爲O(1)的操做,不管集合中有多少個元素,SISMEMBER命令始終能夠極快地返回結果。當值存在時 SISMEMBER命令返回1,當值不存在或鍵不存在時返回0。

(4)集合間運算

SDIFF key [key „]

SINTER key [key „]

SUNION key [key „]

1)SDIFF命令用來對多個集合執行差集運算。集合A與集合B的差集表示爲A−B,表明全部屬於A且不屬於B的元素構成的集合。

2)SINTER命令用來對多個集合執行交集運算。集合A與集合B的交集表示爲A ∩ B,表明全部屬於A 且屬於B的元素構成的集合。

3)SUNION命令用來對多個集合執行並集運算。

3. 實戰應用

(1)存儲文章標籤

考慮到一個文章的全部標籤都是互不相同的,並且展現時對這些標籤的排列順序並無要求,咱們可使用集合類型鍵存儲文章標籤。

具體操做僞代碼以下:

# 給 ID 爲 42 的文章增長標籤:
SADD post:42:tags, 閒言碎語, 技術文章, Java
# 刪除標籤:
SREM post:42:tags, 閒言碎語
# 顯示全部的標籤:
$tags = SMEMBERS post:42:tags
print $tags

 

(2)經過標籤搜索文章

  有時咱們還須要列出某個標籤下的全部文章,甚至須要得到同時屬於某幾個標籤的文章列表,這種需求在傳統關係數據庫中實現起來比較複雜,下面舉一個例子。

  現有3張表,即posts、tags和posts_tags,分別存儲文章數據、標籤、文章與標籤的對應關係。結構分別如表3-五、表3-六、表3-7所示。

 

 

爲了找到同時屬於「Java」、「MySQL」和「Redis」這3個標籤的文章,須要使用以下的SQL語句:

SELECT p.post_title

FROM posts_tags pt,

posts p,

tags t

WHERE pt.tag_id = t.tag_id

AND (t.tag_name IN ('Java', 'MySQL', 'Redis'))

AND p.post_id = pt.post_id

GROUP BY p.post_id HAVING COUNT(p.post_id)=3;

  能夠很明顯看到這樣的 SQL 語句不只效率相對較低,並且不易閱讀和維護。而使用Redis能夠很簡單直接地實現這一需求。

  具體作法是爲每一個標籤使用一個名爲tag:標籤名稱:posts的集合類型鍵存儲標有該標籤的文章ID列表。假設如今有3篇文章,ID分別爲一、二、3,其中ID爲1的文章標籤是「Java」,ID 爲 2 的文章標籤是「Java」、「MySQL」,ID 爲 3 的文章標籤是「Java」、「MySQL」和「Redis」,則有關標籤部分的存儲結構如圖3-18所示:

 

  最簡單的,當須要獲取標記「MySQL」標籤的文章時只須要使用命令 SMEMBERS tag:MySQL:posts便可。若是要實現找到同時屬於Java、MySQL和Redis 3 個標籤的文章,只須要將tag:Java:posts、tag:MySQL:posts和tag:Redis:posts這3個鍵取交集,藉助SINTER命令便可輕鬆完成。

4. 其餘命令

(1)得到集合中元素個數

SCARD key

SCARD命令用來得到集合中的元素個數。

(2)進行集合運算並將結果存儲

 SDIFFSTORE destination key [key …]

 SINTERSTORE destination key [key …]

 SUNIONSTORE destination key [key …]

 SDIFFSTORE命令和SDIFF命令功能同樣,惟一的區別就是前者不會直接返回運算結果,而是將結果存儲在destination鍵中。

SDIFFSTORE命令經常使用於須要進行多步集合運算的場景中,如須要先計算差集再將結果和其餘鍵計算交集。SINTERSTORE和SUNIONSTORE命令與之相似,再也不贅述。

(3)隨機得到集合中的元素

SRANDMEMBER key [count]

SRANDMEMBER命令用來隨機從集合中獲取一個元素,還能夠傳遞count參數來一次隨機得到多個元素。

根據count的正負不一樣,具體表現也不一樣。

1)當count爲正數時,SRANDMEMBER會隨機從集合裏得到count個不重複的元素。若是count的值大於集合中的元素個數,則SRANDMEMBER會返回集合中的所有元素。

2)當count爲負數時,SRANDMEMBER會隨機從集合裏得到|count|個的元素,這些元素有可能相同。

(4)從集合中彈出一個元素

SPOP key

因爲集合類型的元素是無序的,因此 SPOP命令會從集合中隨機選擇一個元素彈出。

5、有序集合類型

1. 介紹

在集合類型的基礎上有序集合類型爲集合中的每一個元素都關聯了一個分數,這使得咱們不只能夠完成插入、刪除和判斷元素是否存在等集合類型支持的操做,還可以得到分數最高(或最低)的前N個元素、得到指定分數範圍內的元素等與分數有關的操做。雖然集合中每一個元素都是不一樣的,可是它們的分數卻能夠相同。

有序集合類型在某些方面和列表類型有些類似。

(1)兩者都是有序的。

(2)兩者均可以得到某一範圍的元素。

可是兩者有着很大的區別,這使得它們的應用場景也是不一樣的。

(1)列表類型是經過鏈表實現的,獲取靠近兩端的數據速度極快,而當元素增多後,訪問中間數據的速度會較慢,因此它更加適合實現如「新鮮事」或「日誌」這樣不多訪問中間元素的應用。

(2)有序集合類型是使用散列表和跳躍表(Skip list)實現的,因此即便讀取位於中間部分的數據速度也很快(時間複雜度是O(log(N)))。

(3)列表中不能簡單地調整某個元素的位置,可是有序集合能夠(經過更改這個元素的分數)。

(4)有序集合要比列表類型更耗費內存。

有序集合類型算得上是Redis的5種數據類型中最高級的類型了,在學習時能夠與列表類型和集合類型對照理解。

2. 命令

(1)增長元素

ZADDkey score member [score member …]

  ZADD 命令用來向有序集合中加入一個元素和該元素的分數,若是該元素已經存在則會用新的分數替換原有的分數。ZADD命令的返回值是新加入到集合中的元素個數(不包含以前已經存在的元素)。

  +inf和-inf分別表示正無窮和負無窮。

(2)得到元素的分數

 ZSCORE key member

(3)得到排名在某個範圍的元素列表

ZRANGE key start stop [WITHSCORES]

ZREVRANGE key start stop [WITHSCORES]

ZRANGE命令會按照元素分數從小到大的順序返回索引從 start到stop之間的全部元素(包含兩端的元素)。負數表明從後向前查找(−1表示最後一個元素)。

若是須要同時得到元素的分數的話能夠在 ZRANGE 命令的尾部加上 WITHSCORES 參數。

ZRANGE命令的時間複雜度爲O(log n+m)(其中n爲有序集合的基數,m爲返回的元素個數)。

(4)得到指定分數範圍的元素

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

ZRANGEBYSCORE 命令參數雖然多,可是都很好理解。該命令按照元素分數從小到大的順序返回分數在min和max之間(包含min和max)的元素:

redis> ZRANGEBYSCORE scoreboard 80 100

1) "Tom"

2) "David"

若是但願分數範圍不包含端點值,能夠在分數前加上「(」符號。例如,但願返回80分到100分的數據,能夠含80分,但不包含100分,則稍微修改一下上面的命令便可:

redis> ZRANGEBYSCORE scoreboard 80 (100

1)  "Tom"

(5)增長某個元素的分數

ZINCRBY key increment member

ZINCRBY 命令能夠增長一個元素的分數,返回值是更改後的分數。例如,想給 Jerry加4分:

redis> ZINCRBY scoreboard 4 Jerry

"60"

increment也能夠是個負數表示減分,例如,給Jerry減4分:

redis> ZINCRBY scoreboard -4 Jerry

"56"

若是指定的元素不存在,Redis 在執行命令前會先創建它並將它的分數賦爲 0 再執行操做。

3. 實戰應用

(1)實現按點擊量排序

要按照文章的點擊量排序,就必須再額外使用一個有序集合類型的鍵來實現。在這個鍵中以文章的 ID 做爲元素,以該文章的點擊量做爲該元素的分數。將該鍵命名爲posts:page.view,每次用戶訪問一篇文章時,博客程序就經過 ZINCRBY posts:page. view 1 文章 ID更新訪問量。

須要按照點擊量的順序顯示文章列表時,有序集合的用法與列表的用法大同小異:

$postsPerPage = 10

$start = ($currentPage - 1) * $postsPerPage

$end = $currentPage * $postsPerPage - 1

$postsID = ZREVRANGE posts:page.view, $start$end

for each $id in $postsID

$postData = HGETALL post:$id

print 文章標題:$postData.title

另外介紹字符串類型時用鍵post:文章ID:page.view來記錄單個文章的訪問量,如今這個鍵已經不須要了,想要得到某篇文章的訪問量能夠經過 ZSCORE posts:page. view文章ID 來實現。

(2)更改文章發佈時間和得到指定時間範圍內的文章列表

爲了可以自由地更改文章發佈時間,能夠採用有序集合類型代替列表類型。天然地,元素仍然是文章的ID,而此時元素的分數則是文章發佈的Unix時間。經過修改元素對應的分數就能夠達到更改時間的目的。另外借助 ZREVRANGEBYSCORE 命令還能夠輕鬆得到指定時間範圍的文章列表,藉助這個功能能夠實現相似WordPress的按月份查看文章的功能。

4. 其餘命令

(1)得到集合中元素的數量

ZCARD key

例如:

redis> ZCARD scoreboard

(integer) 6

(2)得到指定分數範圍內的元素個數

ZCOUNT key min max

例如:

redis> ZCOUNT scoreboard 90 100

(integer) 2

(3)刪除一個或多個元素

ZREM key member [member …]

ZREM命令的返回值是成功刪除的元素數量(不包含原本就不存在的元素)。

(4)按照排名範圍刪除元素

ZREMRANGEBYRANK key start stop

ZREMRANGEBYRANK 命令按照元素分數從小到大的順序(即索引0表示最小的值)刪除處在指定排名範圍內的全部元素,並返回刪除的元素數量。

(5)按照分數範圍刪除元素

ZREMRANGEBYSCORE key min max

ZREMRANGEBYSCORE命令會刪除指定分數範圍內的全部元素,參數min和max的特性和ZRANGEBYSCORE命令中的同樣。返回值是刪除的元素數量。

(6)得到元素的排名

ZRANK key member

ZREVRANK key member

ZRANK命令會按照元素分數從小到大的順序得到指定的元素的排名

(從0開始,即分數最小的元素排名爲0)。如:

redis> ZRANK scoreboard Peter

(integer) 0

ZREVRANK命令則相反(分數最大的元素排名爲0):

redis> ZREVRANK scoreboard Peter

(integer) 4

(7)計算有序集合的交集

ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight…]] [AGGREGATESUM|MIN|MAX]

ZINTERSTORE命令用來計算多個有序集合的交集並將結果存儲在destination鍵中(一樣以有序集合類型存儲),返回值爲destination鍵中的元素個數。

destination鍵中元素的分數是由AGGREGATE參數決定的。

(1)當AGGREGATE是SUM時(也就是默認值),destination鍵中元素

的分數是每一個參與計算的集合中該元素分數的和。

(2)當AGGREGATE是MIN時,destination鍵中元素的分數是每一個參與

計算的集合中該元素分數的最小值。

(3)當AGGREGATE是MAX時,destination鍵中元素的分數是每一個參與

計算的集合中該元素分數的最大值。

ZINTERSTORE命令還可以經過WEIGHTS參數設置每一個集合的權重,每

個集合在參與計算時元素的分數會被乘上該集合的權重。

總結

 

數據類型

 

結構存儲的值

 

結構的讀寫能力

 

博客系統中的應用

 

字符串類型

能夠是字符串、整數或者浮點數

對整個字符串或字符串的其中一部分執行操做;對整數和浮點數執行自增或者自減操做

(1) 博客文章訪問量統計

(2)生成自增ID

 

散列類型

包含鍵值對的無序散列表

添加、獲取、移除單個鍵值對;獲取全部鍵值對

(1)存儲文章數據

(2)存儲文章縮略名

 

列表類型

一個鏈表,鏈表上的每一個節點都包含了一個字符串

從鏈表的兩端推入或者彈出元素;根據偏移量對鏈表進行修剪(trim);讀取單個或多個元素;根據值查找或者移除元素

(1)存儲文章ID列表

(2)存儲評論列表

 

集合類型

包含字符串的無序收集器,而且被包含的每一個字符串都獨一無2、各不相同

添加、獲取、移除單個元素;檢查一個元素是否存在於集合中;計算交集、並集、差集;從集合裏面隨機獲取元素

(1)存儲文章標籤

(2)經過標籤搜索文章

 

有序集合類型

字符串成員與浮點數分值之間的有序映射,元素的排列順序由分值的大小決定

添加、獲取、刪除單個元素;根據分值範圍或者成員來獲取元素

(1)實現按點擊量排序

(2)更改文章發佈時間和得到指定時間範圍內的文章列表

相關文章
相關標籤/搜索