redis簡單使用

主要參考資料:http://wiki.jikexueyuan.com/project/redis-guide/data-type.html
1、redis 安裝
一、在官網下載安裝包
二、解壓安裝包
tar -zvxf redis-3.2.8.tar.gz
三、進行編譯
進入目錄
cd redis-3.2.8;
進行編譯
make
四、安裝redis
進入src目錄
cd src/
編譯安裝
make install
五、後臺運行運、
./redis-server ../redis.conf

數據類型
一、字符創
Redis 字符串是二進制安全的,也就是說,一個 Redis 字符串能夠包含任意類型的數據,一個字符創最大512M長度。
Redis 的字符串類型作很事情:
使用 INCR 命令族 (INCR,DECR,INCRBY),將字符串做爲原子計數器。
使用 APPEND 命令追加字符串。
使用 GETRANGE 和 SETRANGE 命令,使字符串做爲隨機訪問向量 (vectors)。
編碼大量數據到很小的空間,或者使用 GETBIT 和 SETBIT 命令,建立一個基於 Redis 的布隆 (Bloom) 過濾器。
二、列表 (Lists)
Redis 列表僅僅是按照插入順序排序的字符串列表。能夠添加一個元素到 Redis 列表的頭部 (左邊) 或者尾部 (右邊)。
LPUSH 命令用於插入一個元素到列表的頭部,RPUSH 命令用於插入一個元素到列表的尾部
當這兩個命令操做在一個不存在的鍵時,將會建立一個新的列表
例子:
lpush mylist test
lpush mylist test2
rpush mylist test3
列表的最大長度是 223-1 個元素 (4294967295,超過 40 億個元素)。
列表用處
爲社交網絡時間軸 (timeline) 建模,使用 LPUSH 命令往用戶時間軸插入元素,使用 LRANGE 命令得到最近事項。
使用 LPUSH 和 LTRIM 命令建立一個不會超出給定數量元素的列表,只存儲最近的 N 個元素。
列表能夠用做消息傳遞原語,例如,衆所周知的用於建立後臺任務的 Ruby 庫 Resque。
你能夠用列表作更多的事情,這種數據類型支持不少的命令,包括阻塞命令,如 BLPOP。
三、集合 (Sets)
Redis 集合是沒有順序的字符串集合 (collection)。能夠在 O(1) 的時間複雜度添加、刪除和測試元素存在與否 。
Redis 集合具備你須要的不容許重複成員的性質。屢次加入同一個元素到集合也只會有一個拷貝在其中。實際上,這意味着加入一個元素到集合中並不須要檢查元素是否已存在
集合能夠在很短的時間內和已經存在的集合一塊兒計算並集,交集和差集。
用處:
你可使用 Redis 集合追蹤惟一性的事情。你想知道訪問某篇博客文章的全部惟一 IP 嗎?只要 每次頁面訪問時使用 SADD 命令就能夠了。你能夠放心,重複的 IP 是不會被插入進來的。
Redis 集合能夠表示關係。你能夠經過使用集合來表示每一個標籤,來建立一個標籤系統。而後你能夠把全部擁有此標籤的對象的 ID 經過 SADD 命令,加入到表示這個標籤的集合中。你想得到同時擁有三個不一樣標籤的對象的所有 ID 嗎?用 SINTER 就能夠了。
你可使用 SPOP 或 SRANDMEMBER 命令來從集合中隨機抽取元素
四、哈希 / 散列 (Hashes)
Redis 哈希是字符串字段 (field) 與字符串值之間的映射,因此是表示對象的理想數據類型 (例如:一個用戶對象有多個字段,像用戶名,姓氏,年齡等等
例子:
HMSET user:1000 username antirez password P1pp0 age 34
HGETALL user:1000
HSET user:1000 password 12345
HGETALL user:1000
擁有少許字段 (少許指的是大約 100) 的哈希會以佔用不多存儲空間的方式存儲,因此你能夠在一個很小的 Redis 實例裏存儲數百萬的對象。
因爲哈希主要用來表示對象,對象能存儲不少元素,因此你能夠用哈希來作不少其餘的事情。
每一個哈希能夠存儲多達 223-1 個字段值對 (field-value pair)(多於 40 億個)
五、有序集合 (Sorted sets)
Redis 有序集合和 Redis 集合相似,是非重複字符串集合 (collection)。不一樣的是,每個有序集合的成員都有一個關聯的分數 (score),用於按照分數高低排序。儘管成員是惟一的,可是分數是能夠重複的
對有序集合咱們能夠經過很快速的方式添加,刪除和更新元素 (在和元素數量的對數成正比的時間內)。因爲元素是有序的而無需過後排序,你能夠經過分數或者排名 (位置) 很快地來獲取一個範圍內的元素。訪問有序集合的中間元素也是很快的,因此你可使用有序集合做爲一個無重複元素,快速訪問你想要的一切的聰明列表:有序的元素,快速的存在性測試,快速的訪問中間元素!
總之,有序集合能夠在很好的性能下,作不少別的數據庫沒法模擬的事情。
使用有序集合你能夠:
例如多人在線遊戲排行榜,每次提交一個新的分數,你就使用 ZADD 命令更新。你能夠很容易地使用 ZRANGE 命令獲取前幾名用戶,你也能夠用 ZRANK 命令,經過給定用戶名返回其排行。同時使用 ZRANK 和 ZRANGE 命令能夠展現與給定用戶類似的用戶及其分數。以上這些操做都很是的快。
有序集合經常使用來索引存儲在 Redis 內的數據。例如,假設你有不少表示用戶的哈希,你可使用有序集合,用年齡做爲元素的分數,用用戶 ID 做爲元素值,因而你就可使用 ZRANGEBYSCORE 命令很快且垂手可得地檢索出給定年齡區間的全部用戶了。
有序集合或許是最高級的 Redis 數據類型,後續咱們會詳細介紹可用的有序集合命令,也會詳細介紹 Redis 數據類型的更多高級信息。
六、位圖 (Bitmaps) 和超重對數 (HyperLogLogs)
Redis 還支持位圖和超重對數這兩種基於字符串基本類型,但有本身語義的數據類型。

3、詳細講解(上)
Redis 不是一個無格式 (plain) 的鍵值存儲,而是一個支持各類不一樣類型值的數據結構服務器。這就是說,傳統鍵值存儲是關聯字符串值到字符串鍵,可是 Redis 的值不只僅侷限於簡單字符串,還能夠持有更復雜的數據結構。下面列的是 Redis 支持的全部數據結構
二進制安全 (binary-safe) 的字符串。
列表:按照插入順序排序的字符串元素 (element) 的集合 (collection)。一般是鏈表。
集合:惟一的,無序的字符串元素集合。
有序集合:和集合相似,可是每一個字符串元素關聯了一個稱爲分數 (score) 的浮點數。元素老是按照分數排序,因此能夠檢索一個範圍的元素 (例如,給我前 10,或者後 10 個元素)。
哈希:由字段 (field) 及其關聯的值組成的映射。字段和值都是字符串類型。這很是相似於 Ruby 或 Python 中的哈希 / 散列。
位數組 (位圖):使用特殊的命令,把字符串當作位數組來處理:你能夠設置或者清除單個位值,統計所有置位爲 1 的位個數,尋找第一個復位或者置位的位,等等。
超重對數 (HyperLogLog):這是一個用於估算集合的基數 (cardinality,也稱勢,譯者注) 的機率性數據結構。不要懼怕,它比看起來要簡單,稍後爲你揭曉。
後面的全部例子咱們都是使用 redis-cli 工具,這是一個簡單而又方便的命令行工具,用於發送命令給 Redis 服務器
一、Redis 鍵 (Keys)
Redis 鍵是二進制安全的,這意味着你可使用任何二進制序列做爲鍵,從像」foo」 這樣的字符串到一個 JPEG 文件的內容。空字符串也是合法的鍵。
關於鍵的其餘一些規則:
不要使用太長的鍵,例如,不要使用一個 1024 字節的鍵,不只是由於內存佔用,並且在數據集中查找鍵時須要屢次耗時的鍵比較。即便手頭須要匹配一個很大值的存在性,對其進行哈希 (例如使用 SHA1) 是個不錯的主意,尤爲是從內存和帶寬的角度。
不要使用過短的鍵。用」u1000flw」 取代」user:1000:followers」 做爲鍵並無什麼實際意義,後者更具備可讀性,相對於鍵對象自己以及值對象來講,增長的空間微乎其微。然而不能否認,短的鍵會消耗少的內存,你的任務就是要找到平衡點
堅持一種模式 (schema)。例如,」object-type:id」 就不錯,就像」user:1000」。點或者橫線經常使用來鏈接多單詞字段,如」comment:1234:reply.to」,或者」comment:1234:reply-to」。
鍵的最大大小是 512MB
二、Redis 字符串 (Strings)
Redis 字符串是能夠關聯給 redis 鍵的最簡單值類型。字符串是 Memcached 的惟一數據類型,因此新手使用起來也是很天然的。
因爲 Redis 的鍵也是字符串,當咱們使用字符串做爲值的時候,咱們是將一個字符串映射給另外一個字符串。字符串數據類型適用於不少場景,例如,緩存 HTML 片斷或者頁面。
讓咱們用 redis-cli 來玩玩字符串類型 (接下來的例子都是使用 redis-cli)。
> set mykey somevalue
OK
> get mykey
"somevalue"
你能夠看到,咱們使用 SET 和 GET 命令設置和檢索字符串值。注意,若是鍵已經存在,SET 會替換掉該鍵已經存在的值,哪怕這個鍵關聯的是一個非字符串類型的值。SET 執行的是賦值操做。
值能夠是任何類型的字符串 ,例如,你能夠存儲一個 JPEG 圖像。值不能大於 512MB。
SET 命令還有一些以額外的參數形式提供有意思的選項。例如,若是我要求若是鍵存在 (或恰好相反) 則執行失敗,也就是說健不存在才成功:
#若是不存在則能夠插入
> set mykey newval nx
(nil)
#若是存在則能夠插入
> set mykey newval xx
OK
儘管字符串是 Redis 最基本的值類型,你仍能夠執行不少有趣的操做。例如,原子性增加:
> set counter 100 設置counter只爲100
OK
> incr counter 增長1
(integer) 101
> incr counter 增長1
(integer) 102
> incrby counter 50 增長50
(integer) 152
INCR 命令將字符串值解析爲整數,並增長一,最後賦值後做爲新值。還有一些相似的命令 INCRBY,DECR 和 DECRBY。它們以略微不一樣的方式執行,但其內部都是同樣的命令。
爲何說 INCR 命令是原子的?由於即便多個 客戶端對同一個鍵發送 INCR 命令也不會形成競爭條件 (race condition)。例如,必定不會發生客戶端 1 和客戶端 2 同時讀到」10」,都增長到 11,而後設置新值爲 11。最後的結果將會一直是 12,讀 - 增長 - 寫操做在執行時,其餘客戶端此時不會執行相關命令。
有許多操做字符串的命令。例如,GETSET 命令給鍵設置一個新值,同時返回舊值。你可使用這個命令,例如,若是你有一個系統,每當收到一個訪問請求就使用 INRC 來增長一個鍵。你想每隔一個小時收集一次這個信息,而不想漏掉任何一個增加。你可使用 GETSET,將新值賦值爲 0,以後讀取其舊值。
在一個命令中一次設置或者檢索多個鍵有利於減小延遲。爲此有了 MSET 和 MGET 命令:
> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"
當使用 MSET 時,Redis 返回一個值數組。
改變和查詢鍵空間 (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):有限生存時間的鍵
在咱們繼續更復雜的數據結構以前,咱們先拋出一個與類型無關的特性, 稱爲 Redis 過時 。你能夠給鍵設置超時,也就是一個有限的生存時間。當生存時間到了,鍵就會自動被銷燬,就像用戶調用 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) 5秒後執行
(nil)
鍵在兩次 GET 調用期間消失了,由於第二次調用推遲了超過 5 秒。在上面的例子中,咱們使用 EXPIRE 命令設置過時 (也能夠爲一個已經設置過時時間的鍵設置不一樣的過時時間,就像 PERSIST 命令能夠刪除過時時間使鍵永遠存在)。固然咱們也可使用其餘 Redis 命令來建立帶過時時間的鍵。例如使用 SET 選項:
> set key 100 ex 10
OK
> ttl key
(integer) 9
上面的例子中設置 10 秒過時的鍵,值爲字符串 100。而後使用 TTL 命令檢查鍵的生存剩餘時間。
爲了使用毫秒來設置和檢查過時,請查看 PEXPIRE 和 PTTL 命令,以及 SET 命令的所有選項。
4、詳細講解(中)
Redis 列表(Lists)
Redis 的列表是使用鏈表實現的。這意味着,及時你的列表中有上百萬個元素,增長一個元素到列表的頭部或者尾部的操做都是在常量時間完成。使用 LPUSH 命令增長一個新元素到擁有 10 個元素的列表的頭部的速度,與增長到擁有 1000 萬個元素的列表的頭部是同樣的。
缺點又是什麼呢?使用索引下標來訪問一個數組實現的列表很是快(常量時間),可是訪問鏈表實現列表就沒那麼快了(與元素索引下標成正比的大量工做)。
Redis 採用鏈表來實現列表是由於,對於數據庫系統來講,快速插入一個元素到一個很長的列表很是重要。另一個即將描述的優點是,Redis 列表能在常數時間內得到常數長度。
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 命令使用兩個索引下標,分別是返回的範圍的開始和結束元素。兩個索引座標能夠是負數,表示從後往前數,因此 - 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)
列表能夠完成不少任務,兩個有表明性的場景以下:
記住社交網絡中用戶最近提交的更新。
使用生產者消費者模式來進程間通訊,生產者添加項(item)到列表,消費者(一般是 worker)消費項並執行任務。Redis 有專門的列表命令更加可靠和高效的解決這種問題。
例如,兩種流行的 Ruby 庫 resque 和 sidekiq,都是使用 Redis 列表做爲鉤子,來實現後臺做業 (background jobs)。
流行的 Twitter 社交網絡,使用 Redis 列表來存儲用戶最新的微博 (tweets)。
爲了一步一步的描述通用場景,假設你想加速展示照片共享社交網絡主頁的最近發佈的圖片列表。
每次用戶提交一張新的照片,咱們使用 LPUSH 將其 ID 添加到列表。
當用戶訪問主頁時,咱們使用 LRANGE 0 9 獲取最新的 10 張照片。
上限列表(Capped)
不少時候咱們只是想用列表存儲最近的項,隨便這些項是什麼:社交網絡更新,日誌或者任何其餘東西。
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 個元素,其餘的都被拋棄。這可讓你實現一個簡單而又有用的模式,一個添加操做和一個修剪操做一塊兒,實現新增一個元素拋棄超出元素。
LPUSH mylist <some element>
LTRIM mylist 0 999
上面的組合增長一個元素到列表中,同時只持有最新的 1000 個元素。使用 LRANGE 命令你能夠訪問前幾個元素而不用記錄很是老的數據。
注意:儘管 LRANGE 是一個O(N)時間複雜度的命令,訪問列表頭尾附近的小範圍是常量時間的操做。
列表的阻塞操做 (blocking)
列表有一個特別的特性使得其適合實現隊列,一般做爲進程間通訊系統的積木:阻塞操做。
假設你想往一個進程的列表中添加項,用另外一個進程來處理這些項。這就是一般的生產者消費者模式,可使用如下簡單方式實現:
生產者調用 LPUSH 添加項到列表中。
消費者調用 RPOP 從列表提取 / 處理項。
然而有時候列表是空的,沒有須要處理的,RPOP 就返回 NULL。因此消費者被強制等待一段時間並重試 RPOP 命令。這稱爲輪詢(polling),因爲其具備一些缺點,因此不合適在這種狀況下
強制 Redis 和客戶端處理無用的命令 (當列表爲空時的全部請求都沒有執行實際的工做,只會返回 NULL)。
因爲工做者受到一個 NULL 後會等待一段時間,這會延遲對項的處理。
因而 Redis 實現了 BRPOP 和 BLPOP 兩個命令,它們是當列表爲空時 RPOP 和 LPOP 的會阻塞版本:僅當一個新元素被添加到列表時,或者到達了用戶的指定超時時間,才返回給調用者。 這個是咱們在工做者中調用 BRPOP 的例子:
> brpop tasks 5
1) "tasks"
2) "do_something"

上面的意思是」 等待 tasks 列表中的元素,若是 5 秒後尚未可用元素就返回」。
注意,你可使用 0 做爲超時讓其一直等待元素,你也能夠指定多個列表而不只僅只是一個,同時等待多個列表,當第一個列表收到元素後就能獲得通知。
關於 BRPOP 的一些注意事項。
客戶端按順序服務:第一個被阻塞等待列表的客戶端,將第一個收到其餘客戶端添加的元素,等等。
與 RPOP 的返回值不一樣:返回的是一個數組,其中包括鍵的名字,由於 BRPOP 和 BLPOP 能夠阻塞等待多個列表的元素。
若是超時時間到達,返回 NULL。
還有更多你須要知道的關於列表和阻塞選項,建議你閱讀下面的頁面:
使用 RPOLPUSH 構建更安全的隊列和旋轉隊列。
BRPOPLPUSH 命令是其阻塞變種命令。
自動建立和刪除鍵
到目前爲止的例子中,咱們尚未在添加元素前建立一個空的列表,也沒有刪除一個沒有元素的空列表。要注意,當列表爲空時 Redis 將刪除該鍵,當向一個不存在的列表鍵(如使用 LPUSH)添加一個元素時,將建立一個空的列表。
這並不僅是針對列表,適用於全部 Redis 多元素組成的數據類型,所以適用於集合,有序集合和哈希。
基本上咱們能夠歸納爲三條規則:
當咱們向聚合(aggregate)數據類型添加一個元素,若是目標鍵不存在,添加元素前將建立一個空的聚合數據類型。
當咱們從聚合數據類型刪除一個元素,若是值爲空,則鍵也會被銷燬。
調用一個像 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)
> 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"
哈希就是字段值對(fields-values pairs)的集合。因爲哈希容易表示對象,事實上哈希中的字段的數量並無限制,因此你能夠在你的應用程序以不一樣的方式來使用哈希。
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 集合是無序的字符串集合 (collections)。SADD 命令添加元素到集合。還能夠對集合執行不少其餘的操做,例如,測試元素是否存在,對多個集合執行交集、並集和差集,等等。
> sadd myset 1 2 3
(integer) 3
> smembers myset
1. 3
2. 1
3. 2
咱們向集合總添加了 3 個元素,而後告訴 Redis 返回全部元素。如你所見,他們沒有排序,Redis 在每次調用時按隨意順序返回元素,由於沒有與用戶有任何元素排序協議。
咱們有測試成員關係的命令。一個指定的元素存在嗎?
> sismember myset 3
(integer) 1
> sismember myset 30
(integer) 0
「3」 是集合中的成員,」30」 則不是。
假設,咱們想標記新聞。若是咱們的 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
例如,咱們想獲取全部被標籤 1,2,10 和 27 同時標記的對象列表。咱們可使用 SINTER 命令實現這個,也就是對不一樣的集合執行交集。咱們只須要:
> sinter tag:1:news tag:2:news
1) "1000"
並不只僅是交集操做,你也能夠執行並集,差集,隨機抽取元素操做等等。
抽取一個元素的命令是 SPOP,就方便爲不少問題建模。例如,爲了實現一個基於 web 的撲克遊戲,你能夠將你的一副牌表示爲集合。假設咱們使用一個字符前綴表示(C)lubs 梅花, (D)iamonds 方塊,(H)earts 紅心,(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
如今咱們爲每位選手提供 5 張牌。SPOP 命令刪除一個隨機元素,返回給客戶端,是這個場景下的最佳操做。
然而,若是咱們直接對這副牌調用,下一局咱們須要再填充一副牌,這個可能不太理想。因此咱們一開始要複製一下 deck 鍵的集合到 game:1:deck 鍵。
這是經過使用 SUNIONSTORE 命令完成的,這個命令一般對多個集合執行交集,而後把結果存儲在另外一個集合中。而對單個集合求交集就是其自身,因而我能夠這樣拷貝個人這副牌:
> sunionstore game:1:deck deck
(integer) 52
如今咱們準備好爲第一個選手提供 5 張牌:
> 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"
只有一對 jack,不太理想……
如今是時候介紹提供集合中元素數量的命令。這個在集合理論中稱爲集合的基數(cardinality,也稱集合的勢),因此相應的 Redis 命令稱爲 SCARD。
> scard game:1:deck
(integer) 47
數學計算式爲:52 - 5 = 47。
當你只須要得到隨機元素而不須要從集合中刪除,SRANDMEMBER 命令則適合你完成任務。它具備返回重複的和非重複的元素的能力
5、詳細講解(下)
Redis 有序集合 (Sorted sets)
有序集合相似於集合和哈希的混合體的一種數據類型。像集合同樣,有序集合由惟一的,不重複的字符串元素組成,在某種意義上,有序集合也就是集合。
集合中的每一個元素是無序的,但有序集合中的每一個元素都關聯了一個浮點值,稱爲分數(score,這就是爲何該類型也相似於哈希,由於每個元素都映射到一個值)。
此外,有序集合中的元素是按序存儲的(不是請求時才排序的,順序是依賴於表示有序集合的數據結構)。他們按照以下規則排序:
若是 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 命令也是可變參數的,因此你能夠自由的指定多個分數值對(score-value pairs),儘管上面的例子中並無使用。
使用排序集合能夠很容易返回按照出生年份排序的黑客列表,由於他們已是排序好的。 實現注意事項:有序集合是經過雙端(dual-ported)數據結構實現的,包括跳躍表(skiplist,後續文章會詳細介紹,譯者注)和哈希表(hashtable),因此咱們每次添加元素時 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"
範圍操做 (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 也許不是最合適的命令名,可是很是有用,返回刪除的元素數目。
另外一個很是有用的操做是用來獲取有序集合中元素排行的操做。也就是能夠詢問集合中元素的排序位置。
> zrank hackers "Anita Borg"
(integer) 4
ZREVRANK 命令用來按照降序排序返回元素的排行。
字典分數 (Lexicographical scores)
最近的 Redis2.8 版本引入了一個新的特性,假定集合中的元素都具備相同的分數,容許按字典順序獲取範圍(元素按照 C 語言中的 memcmp 函數進行比較,所以能夠保證沒有整理,每一個 Redis 實例會有相同的輸出)。
操做字典順序範圍的主要命令是 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 位大端(big endian)數字組成的 8 字節前綴。因爲數字是大端編碼,字典順序排序(原始 raw 字節順序)其實就是數字順序,你能夠在 128 位空間查詢範圍,獲取元素後拋棄前綴。若是你想在一個更正式的例子中瞭解這個特性,能夠看看 Redis 自動完成範例(後續獻上,譯者注)。
更新分數:排行榜 (leader boards)
這一部分是開始新的主題前最後一個關於有序集合的內容。有序集合的分數能夠隨時更新。對一個存在於有序集合中的元素再次調用 ZADD,將會在 O(log(N))時間複雜度更新他的分數 (和位置),因此有序集合適合於常常更新的場合。
因爲這個特性,一般的一個使用場景就是排行榜。最典型的應用就是 facebook 遊戲,你能夠組合使用按分數高低存儲用戶,以及獲取排名的操做,來展現前 N 名的用戶以及用戶在排行榜上的排行(你是第 4932 名最佳分數)。









































































html

相關文章
相關標籤/搜索