今天給學弟學妹講背景讨論班,為了推進工作室背景開發技術的發展,引進了Redis技術,主要參考了《Redis入門指南(第二版)》這本書的第三章,這本書寫的非常生動,在裡面提煉并擴充了一些内容作為讨論班講義。
熱身:系統級指令
1. 獲得符合規則的鍵名清單
模式比對
産品的緩存:product+"."+....; => keys product*
訂單的緩存:order+"."+...; => keys order*
使用 KEYS *能獲得Redis中的所有鍵
提示:KEYS指令需要周遊Redis中的所有鍵,當鍵的數量較多時會影響性能,不建議在生産環境中使用。Redis不區分指令大小寫。

2. 判斷一個鍵是否存在
如果鍵存在則傳回整數類型1,否則傳回0。
3. 删除鍵
可以删除一個或多個鍵,傳回值是删除的鍵的個數。
4. 獲得鍵值的資料類型
5.清空資料庫
6.過期時間
如果要做緩存,那麼一定要有一個過期時間。
7.檢視剩餘存活時間。
ttl 檢視key還有多長存活時間。(秒為機關)
為了讓你更全面地了解 Redis的每種資料類型,接下來我會先講解如何将Redis作為資料庫使用,但是實際上 Redis可不隻是資料庫這麼簡單,更多的公司和團隊将 Redis用作緩存和隊列系統,而這部分内容等你掌握了Redis的基礎後我會再進行介紹,下面将介紹redis的五大資料類型,并通過實戰一個部落格管理系統的原理來講解他們的應用。
一、字元串類型
1. 介紹
字元串類型是 Redis 中最基本的資料類型,它能存儲任何形式的字元串,包括二進制資料。你可以用其存儲使用者的郵箱、JSON 化的對象甚至是一張圖檔。一個字元串類型鍵允許存儲的資料的最大容量是512 MB。
字元串類型是其他4種資料類型的基礎,其他資料類型和字元串類型的差别從某種角度來說隻是組織字元串的形式不同。例如,清單類型是以清單的形式組織字元串,而集合類型是以集合的形式組織字元串。
2. 指令
(1)指派與取值
key等于”hello”在Redis中是這樣表示的:
想要讀取鍵值則更簡單:
當鍵不存在時會傳回空結果。
(2) 遞增數字
前面說過字元串類型可以存儲任何形式的字元串,當存儲的字元串是整數形式時, Redis 提供了一個實用的指令 INCR,其作用是讓目前鍵值遞增,并傳回遞增後的值,用法為:
當要操作的鍵不存在時會預設鍵值為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指令與INCR指令基本一樣,隻不過前者可以通過increment參數指定一次增加的數值,如:
(2)減少指定的整數
DECR指令與INCR指令用法相同,隻不過是讓鍵值遞減,例如:
(3)增加指定浮點數
INCRBYFLOAT指令類似INCRBY指令,差别是前者可以遞增一個雙精度浮點數,如:
(4)向尾部追加值
APPEND作用是向鍵值的末尾追加value。如果鍵不存在則将該鍵的值設定為value,即相當于 SET key value。傳回值是追加後字元串的總長度。
如:
此時 key 的值是"hello world!"。
APPEND 指令的第二個參數加了雙引号,原因是該參數包含空格,在redis-cli中輸入需要雙引号以示區分。
(5)擷取字元串長度
STRLEN指令傳回鍵值的長度,如果鍵不存在則傳回0。
例如:
字元串類型可以存儲二進制資料,是以它可以存儲任何編碼的字元串。例子中Redis接收到的是使用UTF-8編碼的中文,由于“你”和“好”兩個字的UTF-8編碼的長度都是3,是以此例中會傳回6。
(6)同時獲得/設定多個鍵值
MGET/MSET 與GET/SET 相似,不過MGET/MSET 可以同時獲得/設定多個鍵的鍵值。
(7)位操作
一個位元組由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再進行存儲。
二、散列類型
我們現在已經知道 Redis 是采用字典結構以鍵值對的形式存儲資料的,而散列類型(hash)的鍵值也是一種字典結構,其存儲了字段(field)和字段值的映射,但字段值隻能是字元串,不支援其他資料類型,換句話說,散列類型不能嵌套其他的資料類型。一個散列類型鍵可以包含至多2^32−1個字段。
除了散列類型,Redis 的其他資料類型同樣不支援資料類型嵌套。比如集合類型的每個元素都隻能是字元串,不能是另一個集合或散清單等。
散列類型适合存儲對象:使用對象類别和 ID 構成鍵名,使用字段表示對象的屬性,而字段值則存儲屬性值。例如要存儲ID為2的汽車對象,可以分别使用名為color、name和price的3個字段來存儲該輛汽車的顔色、名稱和價格。
回想關系資料庫中存儲汽車對象:
增加一個屬性後對于ID為2和3的兩條字段而言data字段是備援的。
Redis 的散列類型則不存在這個問題。雖然我們在圖 3-5 中描述了汽車對象的存儲結構,但是這個結構隻是人為的約定,Redis并不要求每個鍵都依據此結構存儲,我們完全可以自由地為任何鍵增減字段而不影響其他鍵。
(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指令。如:
(2)判斷字段是否存在
HEXISTS指令用來判斷一個字段是否存在。如果存在則傳回1,否則傳回0(如果鍵不存在也會傳回0)。
(3)當字段不存在時指派
HSETNX指令與HSET指令類似,差別在于如果字段已經存在,HSETNX指令将不執行任何操作。
(4)增加指定數字
(5)删除字段
HDEL指令可以删除一個或多個字段,傳回值是被删除的字段個數:
(1)存儲文章資料
可以使用 HGETALL 指令獲得一個對象的所有字段,删除一個對象時隻需要删除一個鍵,另外存儲同樣的資料散列類型往往比字元串類型更加節約空間。
(2)存儲文章縮略名
每個文章的縮略名必須是唯一的,是以在釋出文章時程式需要驗證使用者輸入的縮略名是否存在,同時也需要通過縮略名獲得文章的ID。
我們可以使用一個散列類型的鍵slug.to.id來存儲文章縮略名和ID之間的映射關系。其中字段用來記錄縮略名,字段值用來記錄縮略名對應的ID。這樣就可以使用HEXISTS指令來判斷縮略名是否存在,使用HGET指令來獲得縮略名對應的文章ID了。
(1)隻擷取字段名或字段值
(2)獲得字段數量
三、清單類型
清單類型(list)可以存儲一個有序的字元串清單,常用的操作是向清單兩端添加元素,或者獲得清單的某一個片段。
清單類型内部是使用雙向連結清單(double linked list)實作的,是以向清單兩端添加元素的時間複雜度為O(1),擷取越接近兩端的元素速度就越快。這意味着即使是一個有幾千萬個元素的清單,擷取頭部或尾部的10條記錄也是極快的(和從隻有20個元素的清單中擷取頭部或尾部的10條記錄的速度是一樣的),不過使用連結清單的代價是通過索引通路元素比較慢。
這種特性使清單類型能非常快速地完成關系資料庫難以應付的場景:
如社交網站的新鮮事,我們關心的隻是最新的内容,使用清單類型存儲,即使新鮮事的總數達到幾千萬個,擷取其中最新的100條資料也是極快的。同樣因為在兩端插入記錄的時間複雜度是O(1),清單類型也适合用來記錄日志,可以保證加入新日志的速度不會受到已有日志數量的影響。
與散列類型鍵最多能容納的字段數量相同,一個清單類型鍵最多能容納2^32−1個元素。
2.指令
(1)向清單兩端增加元素
LPUSH指令用來向清單左邊增加元素,傳回值表示增加元素後清單的長度。
LPUSH指令還支援同時增加多個元素,例如:
LPUSH會先向清單左邊加入"2",然後再加入"3",是以此時numbers鍵中的資料如圖3-9所示。
向清單右邊增加元素的話則使用RPUSH指令。
(2)從清單兩端彈出元素
有進有出,LPOP指令可以從清單左邊彈出一個元素。LPOP指令執行兩步操作:第一步是将清單左邊的元素從清單中移除,第二步是傳回被移除的元素值。
例如,從 numbers清單左邊彈出一個元素(也就是"3"):
RPOP指令可以從清單右邊彈出一個元素。
結合上面提到的 4 個指令可以使用清單類型來模拟棧和隊列的操作:如果想把清單當做棧,則搭配使用LPUSH和LPOP或RPUSH和RPOP,如果想當成隊列,則搭配使用LPUSH和RPOP或RPUSH和LPOP。
(3)擷取清單中元素的個數
當鍵不存在時LLEN會傳回0:
LLEN 指令的功能類似SQL語句 SELECT COUNT(*) FROM table_name,但是 LLEN的時間複雜度為O(1),使用時Redis會直接讀取現成的值,而不需要像部分關系資料庫(如使用InnoDB存儲引擎的MySQL表)那樣需要周遊一遍資料表來統計條目數量。
(4)獲得清單片段
LRANGE指令是清單類型最常用的指令之一,它能夠獲得清單中的某一片段。LRANGE指令将傳回索引從 start到 stop之間的所有元素(包含兩端的元素)。與大多數人的直覺相同,Redis的清單起始索引為0。
LRANGE指令也支援負索引,表示從右邊開始計算序數,如"−1"表示最右邊第一個元素,"-2"表示最右邊第二個元素,依次類推。
顯然,LRANGE numbers 0 -1 可以擷取清單中的所有元素。
另外一些特殊情況如下:
1)如果start的索引位置比stop的索引位置靠後,則會傳回空清單。
2)如果stop大于實際的索引範圍,則會傳回到清單最右邊的元素。
(5)删除清單中指定的值
LREM指令會删除清單中前count個值為value的元素,傳回值是實際删除的元素個數。根據count值的不同,LREM指令的執行方式會略有差異。
1)當 count > 0時 LREM 指令會從清單左邊開始删除前 count 個值為 value的元素。
2)當 count < 0時 LREM 指令會從清單右邊開始删除前|count|個值為 value 的元素。
3)當 count = 0是 LREM指令會删除所有值為 value的元素。
(1)存儲文章ID清單
我們使用清單類型鍵posts:list記錄文章ID清單。當釋出新文章時使用LPUSH指令把新文章的ID加入這個清單中,另外删除文章時也要記得把清單中的文章ID 删除,就像這樣:
LREM posts:list 1 要删除的文章的ID
有了文章 ID清單,就可以使用 LRANGE指令來實作文章的分頁顯示了。
(2)存儲評論清單
我們可以将一條評論的各個元素序列化成字元串後作為清單類型鍵中的元素來存儲。使用清單類型鍵post:文章的ID:comments來存儲某個文章的所有評論。
釋出評論的僞代碼如下(以ID為42的文章為例):
讀取評論時同樣使用LRANGE指令即可。
4.其他指令
(1)獲得/設定指定索引的元素值
LINDEX key index
LSET key index value
如果要将清單類型當作數組來用,LINDEX指令是必不可少的。LINDEX指令用來傳回指定索引的元素,索引從0開始。
LSET是另一個通過索引操作清單的指令,它會将索引為index的元素指派為value。
(2)隻保留清單指定片段
LTRIM key start end LTRIM 指令可以删除指定索引範圍之外的所有元素,其指定清單範圍的方法和LRANGE指令相同。
LTRIM指令常和LPUSH指令一起使用來限制清單中元素的數量,比如記錄日志時我們希望隻保留最近的100條日志,則每次加入新元素時調用一次LTRIM指令即可:
(3)向清單中插入元素
LINSERT 指令首先會在清單中從左到右查找值為 pivot 的元素,然後根據第二個參數是BEFORE還是AFTER來決定将value插入到該元素的前面還是後面。
LINSERT指令的傳回值是插入後清單的元素個數。
(4)将元素從一個清單轉到另一個清單
RPOPLPUSH是個很有意思的指令,從名字就可以看出它的功能:先執行RPOP指令再執行LPUSH指令。RPOPLPUSH指令會先從source清單類型鍵的右邊彈出一個元素,然後将其加入到destination清單類型鍵的左邊,并傳回這個元素的值,整個過程是原子的。
當把清單類型作為隊列使用時,RPOPLPUSH 指令可以很直覺地在多個隊列中傳遞資料。當source和destination相同時,RPOPLPUSH指令會不斷地将隊尾的元素移到隊首,借助這個特性我們可以實作一個網站監控系統:
使用一個隊列存儲需要監控的網址,然後監控程式不斷地使用 RPOPLPUSH 指令循環取出一個網址來測試可用性。這裡使用RPOPLPUSH指令的好處在于在程式執行過程中仍然可以不斷地向網址清單中加入新網址,而且整個系統容易擴充,允許多個用戶端同時處理隊列。
四、集合類型
1.介紹
集合的概念高中的數學課就學習過。在集合中的每個元素都是不同的,且沒有順序。一個集合類型(set)鍵可以存儲至多2^32 −1個(相信這個數字對大家來說已經很熟悉了)字元串。
集合類型的常用操作是向集合中加入或删除元素、判斷某個元素是否存在等,由于集合類型在Redis内部是使用值為空的散清單(hash table)實作的,是以這些操作的時間複雜度都是O(1)。最友善的是多個集合類型鍵之間還可以進行并集、交集和差集運算,稍後就會看到靈活運用這一特性帶來的便利。
(1)增加/删除元素
SADD 指令用來向集合中增加一個或多個元素,如果鍵不存在則會自動建立。因為在一個集合中不能有相同的元素,是以如果要加入的元素已經存在于集合中就會忽略這個元素。本指令的傳回值是成功加入的元素數量(忽略的元素不計算在内)。
SREM指令用來從集合中删除一個或多個元素,并傳回删除成功的個數。
(2)獲得集合中的所有元素
SMEMBERS指令會傳回集合中的所有元素。
(3)判斷元素是否在集合中
判斷一個元素是否在集合中是一個時間複雜度為O(1)的操作,無論集合中有多少個元素,SISMEMBER指令始終可以極快地傳回結果。當值存在時 SISMEMBER指令傳回1,當值不存在或鍵不存在時傳回0。
(4)集合間運算
1)SDIFF指令用來對多個集合執行差集運算。集合A與集合B的差集表示為A−B,代表所有屬于A且不屬于B的元素構成的集合。
2)SINTER指令用來對多個集合執行交集運算。集合A與集合B的交集表示為A ∩ B,代表所有屬于A 且屬于B的元素構成的集合。
3)SUNION指令用來對多個集合執行并集運算。
(1)存儲文章标簽
考慮到一個文章的所有标簽都是互不相同的,而且展示時對這些标簽的排列順序并沒有要求,我們可以使用集合類型鍵存儲文章标簽。
具體操作僞代碼如下:
(2)通過标簽搜尋文章
有時我們還需要列出某個标簽下的所有文章,甚至需要獲得同時屬于某幾個标簽的文章清單,這種需求在傳統關系資料庫中實作起來比較複雜,下面舉一個例子。
現有3張表,即posts、tags和posts_tags,分别存儲文章資料、标簽、文章與标簽的對應關系。結構分别如表3-5、表3-6、表3-7所示。
為了找到同時屬于“Java”、“MySQL”和“Redis”這3個标簽的文章,需要使用如下的SQL語句:
可以很明顯看到這樣的 SQL 語句不僅效率相對較低,而且不易閱讀和維護。而使用Redis可以很簡單直接地實作這一需求。
具體做法是為每個标簽使用一個名為tag:标簽名稱:posts的集合類型鍵存儲标有該标簽的文章ID清單。假設現在有3篇文章,ID分别為1、2、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指令即可輕松完成。
(1)獲得集合中元素個數
SCARD指令用來獲得集合中的元素個數。
(2)進行集合運算并将結果存儲
SDIFFSTORE指令和SDIFF指令功能一樣,唯一的差別就是前者不會直接傳回運算結果,而是将結果存儲在destination鍵中。
SDIFFSTORE指令常用于需要進行多步集合運算的場景中,如需要先計算差集再将結果和其他鍵計算交集。SINTERSTORE和SUNIONSTORE指令與之類似,不再贅述。
(3)随機獲得集合中的元素
SRANDMEMBER指令用來随機從集合中擷取一個元素,還可以傳遞count參數來一次随機獲得多個元素。
根據count的正負不同,具體表現也不同。
1)當count為正數時,SRANDMEMBER會随機從集合裡獲得count個不重複的元素。如果count的值大于集合中的元素個數,則SRANDMEMBER會傳回集合中的全部元素。
2)當count為負數時,SRANDMEMBER會随機從集合裡獲得|count|個的元素,這些元素有可能相同。
(4)從集合中彈出一個元素
由于集合類型的元素是無序的,是以 SPOP指令會從集合中随機選擇一個元素彈出。
五、有序集合類型
在集合類型的基礎上有序集合類型為集合中的每個元素都關聯了一個分數,這使得我們不僅可以完成插入、删除和判斷元素是否存在等集合類型支援的操作,還能夠獲得分數最高(或最低)的前N個元素、獲得指定分數範圍内的元素等與分數有關的操作。雖然集合中每個元素都是不同的,但是它們的分數卻可以相同。
有序集合類型在某些方面和清單類型有些相似。
(1)二者都是有序的。
(2)二者都可以獲得某一範圍的元素。
但是二者有着很大的差別,這使得它們的應用場景也是不同的。
(1)清單類型是通過連結清單實作的,擷取靠近兩端的資料速度極快,而當元素增多後,通路中間資料的速度會較慢,是以它更加适合實作如“新鮮事”或“日志”這樣很少通路中間元素的應用。
(2)有序集合類型是使用散清單和跳躍表(Skip list)實作的,是以即使讀取位于中間部分的資料速度也很快(時間複雜度是O(log(N)))。
(3)清單中不能簡單地調整某個元素的位置,但是有序集合可以(通過更改這個元素的分數)。
(4)有序集合要比清單類型更耗費記憶體。
有序集合類型算得上是Redis的5種資料類型中最進階的類型了,在學習時可以與清單類型和集合類型對照了解。
(1)增加元素
ZADD 指令用來向有序集合中加入一個元素和該元素的分數,如果該元素已經存在則會用新的分數替換原有的分數。ZADD指令的傳回值是新加入到集合中的元素個數(不包含之前已經存在的元素)。
+inf和-inf分别表示正無窮和負無窮。
(2)獲得元素的分數
(3)獲得排名在某個範圍的元素清單
ZRANGE指令會按照元素分數從小到大的順序傳回索引從 start到stop之間的所有元素(包含兩端的元素)。負數代表從後向前查找(−1表示最後一個元素)。
如果需要同時獲得元素的分數的話可以在 ZRANGE 指令的尾部加上 WITHSCORES 參數。
ZRANGE指令的時間複雜度為O(log n+m)(其中n為有序集合的基數,m為傳回的元素個數)。
(4)獲得指定分數範圍的元素
ZRANGEBYSCORE 指令參數雖然多,但是都很好了解。該指令按照元素分數從小到大的順序傳回分數在min和max之間(包含min和max)的元素:
如果希望分數範圍不包含端點值,可以在分數前加上“(”符号。例如,希望傳回80分到100分的資料,可以含80分,但不包含100分,則稍微修改一下上面的指令即可:
(5)增加某個元素的分數
ZINCRBY 指令可以增加一個元素的分數,傳回值是更改後的分數。例如,想給 Jerry加4分:
increment也可以是個負數表示減分,例如,給Jerry減4分:
如果指定的元素不存在,Redis 在執行指令前會先建立它并将它的分數賦為 0 再執行操作。
(1)實作按點選量排序
要按照文章的點選量排序,就必須再額外使用一個有序集合類型的鍵來實作。在這個鍵中以文章的 ID 作為元素,以該文章的點選量作為該元素的分數。将該鍵命名為posts:page.view,每次使用者通路一篇文章時,部落格程式就通過 ZINCRBY posts:page. view 1 文章 ID更新通路量。
需要按照點選量的順序顯示文章清單時,有序集合的用法與清單的用法大同小異:
另外介紹字元串類型時用鍵post:文章ID:page.view來記錄單個文章的通路量,現在這個鍵已經不需要了,想要獲得某篇文章的通路量可以通過 ZSCORE posts:page. view文章ID 來實作。
(2)更改文章釋出時間和獲得指定時間範圍内的文章清單
為了能夠自由地更改文章釋出時間,可以采用有序集合類型代替清單類型。自然地,元素仍然是文章的ID,而此時元素的分數則是文章釋出的Unix時間。通過修改元素對應的分數就可以達到更改時間的目的。另外借助 ZREVRANGEBYSCORE 指令還可以輕松獲得指定時間範圍的文章清單,借助這個功能可以實作類似WordPress的按月份檢視文章的功能。
(1)獲得集合中元素的數量
(2)獲得指定分數範圍内的元素個數
(3)删除一個或多個元素
ZREM指令的傳回值是成功删除的元素數量(不包含本來就不存在的元素)。
(4)按照排名範圍删除元素
ZREMRANGEBYRANK 指令按照元素分數從小到大的順序(即索引0表示最小的值)删除處在指定排名範圍内的所有元素,并傳回删除的元素數量。
(5)按照分數範圍删除元素
ZREMRANGEBYSCORE指令會删除指定分數範圍内的所有元素,參數min和max的特性和ZRANGEBYSCORE指令中的一樣。傳回值是删除的元素數量。
(6)獲得元素的排名
ZRANK指令會按照元素分數從小到大的順序獲得指定的元素的排名
(從0開始,即分數最小的元素排名為0)。如:
redis> ZRANK scoreboard Peter
(integer) 0
ZREVRANK指令則相反(分數最大的元素排名為0):
(7)計算有序集合的交集
ZINTERSTORE指令用來計算多個有序集合的交集并将結果存儲在destination鍵中(同樣以有序集合類型存儲),傳回值為destination鍵中的元素個數。
destination鍵中元素的分數是由AGGREGATE參數決定的。
(1)當AGGREGATE是SUM時(也就是預設值),destination鍵中元素
的分數是每個參與計算的集合中該元素分數的和。
(2)當AGGREGATE是MIN時,destination鍵中元素的分數是每個參與
計算的集合中該元素分數的最小值。
(3)當AGGREGATE是MAX時,destination鍵中元素的分數是每個參與
計算的集合中該元素分數的最大值。
ZINTERSTORE指令還能夠通過WEIGHTS參數設定每個集合的權重,每
個集合在參與計算時元素的分數會被乘上該集合的權重。
總結
資料類型
結構存儲的值
結構的讀寫能力
部落格系統中的應用
字元串類型
可以是字元串、整數或者浮點數
對整個字元串或字元串的其中一部分執行操作;對整數和浮點數執行自增或者自減操作
散列類型
包含鍵值對的無序散清單
添加、擷取、移除單個鍵值對;擷取所有鍵值對
清單類型
一個連結清單,連結清單上的每個節點都包含了一個字元串
從連結清單的兩端推入或者彈出元素;根據偏移量對連結清單進行修剪(trim);讀取單個或多個元素;根據值查找或者移除元素
集合類型
包含字元串的無序收集器,并且被包含的每個字元串都獨一無二、各不相同
添加、擷取、移除單個元素;檢查一個元素是否存在于集合中;計算交集、并集、差集;從集合裡面随機擷取元素
有序集合類型
字元串成員與浮點數分值之間的有序映射,元素的排列順序由分值的大小決定
添加、擷取、删除單個元素;根據分值範圍或者成員來擷取元素