redis學習筆記(三):列表、集合、有序集合

使用理解基本API

redis提供了5種數據結構,理解每次數據結構的特色在開發和運維中是很重要的.使用redis版本:3.0.7javascript

本章內容以下:java

  1. redis列表redis

  2. redis集合shell

  3. redis有序集合數據結構

1.1 列表

列表(list)類型是用來存儲多個字符串,以下圖A,B,C,D四個元素從左到右組成一個有序的集合.列表中的每一個字符串被稱爲元素(element),一個列表最多能夠存儲(2的32次方)-1個元素.在redis中,能夠對列表兩端插入(push)和彈出(pop),還能夠獲取指定範圍的元素列表、獲取指定全部下標的元素等.app

列表

列表類型有兩個特色:負載均衡

  1. 列表中的元素是有序的,這就意味着能夠經過索引下標獲取某個元素或者某個範圍內的元素列表.運維

  2. 列表中的元素能夠是重複的.編碼

1.1.1 命令

1) 插入命令

(1) 從右邊插入元素.spa

rpush key value [value...]

例:
向列表插入a,b,c三個元素.
從右邊插入元素

lrange key 0 -1命令能夠獲取列表中全部的元素.

獲取全部元素

(2) 從左邊插入元素.
使用方法與rpush同樣,從左側插入.

lpush key value [value....]

例:
從左邊插入元素

2) 查詢命令

(1) 查詢指定範圍內的元素列表

lrange key start end

lrange操做會獲取列表指定索引範圍全部的元素.索引下標有兩個特色:第一,索引下標從左到右分別是0N-1,可是從右到左分別是-1-N.第二,lrange中的end選項包含了自身.
例:
查詢指定範圍內的元素列表

(2) 獲取列表指定索引下的元素

lindex key index

例:

獲取列表指定索引下的元素

(3) 獲取列表長度

llen key

例:

獲取列表長度

3) 刪除命令

(1) 從列表左側或右側彈出元素.

以下操做是將列表最左側與右側的元素彈出來.

從列表左側或右側彈出元素

(2) 刪除指定元素

lrem key count value

lrem命令會從列表中找到等於value的元素進行刪除,根據count的不一樣分爲三種:

  1. count>0,從列表中刪除指定數量(count)的元素.

  2. count<0,從列表中刪除count絕對值數量的元素.

  3. count=0,刪除全部.
    例:

指定元素數量:
刪除指定元素數量

全部元素:
刪除全部元素

(3) 按照索引範圍修剪列表

ltrim key start end

例如,下面操做會保留列表第二個到第六個元素:

按照索引範圍修剪列表

4)修改命令

修改指定索引下標的元素:

lset key index value

例:
修改第一個元素的值爲c.
修改指定索引下標的元素

4) 阻塞操做

阻塞式彈出:

blpop key [key...] timeout
    brpop key [key...] timeout

blpopbrpop命令是lpoprpop命令的阻塞版本,他除了彈出方向不一樣,使用方法基本相同,因此下面以brpop命令進行說明,brpop命令包含兩個參數:

  • key [key...]:多個列表的鍵.

  • timeout:阻塞時間(單位爲).

1)列表爲空:若是timeout等於3,那麼客戶端等到三秒後返回,若是timeout=0,那麼客戶端將一直阻塞,直到彈出成功.

列表爲空

2)列表不爲空:客戶端會馬上返回.

列表不爲空

在使用阻塞彈出命令時,有兩點須要注意.

第一點:若是是多個鍵,那麼會從左到右遍歷鍵,一旦有一個鍵能彈出元素客戶端就會馬上返回.
第二點:若是多個客戶端同時對一個鍵進行操做,那麼最早執行命令的客戶端能夠獲取到值.

1.1.2 內部編碼

列表類型的內部編碼有兩種:

編碼名 編碼描述
ziplist(壓縮列表) 當列表的元素個數大於list-max-ziplist-entries配置(默認爲512個),同時列表中每一個元素的長度小於list-max-ziplist-value配置(默認爲64字節).
linkedlist(鏈表) 當列表的長度或值得大小不知足ziplist的要求,redis會採用linkedlist爲列表的內部實現編碼.

1.1.3 使用場景

  1. 消息隊列:redislpush-brpop命令組合便可實現阻塞隊列,生產者客戶端使用lpush命令向列表插入元素.消費者客戶端使用brpop命令阻塞式的"搶"列表中的尾部元素.多個客戶端保證消息的負載均衡與可用性.
    clipboard.png

  2. 文章列表:每一個用戶都有屬於本身的文章列表.此時能夠考慮使用列表,由於列表不可是有序的,同時支持使用lrange按照索引範圍獲取多個元素.
    僞代碼:

var articles = redis.lrange('user:1:acticles',0,9);
    articles.forEach(function(){
        // 遍歷操做
    });

開發提示:列表的使用場景有不少如: lpush+lpop=Stack(棧)、lpush+rpop=queue(隊列)、lpush+brpop=message queue(消息隊列)、lpush+ltrim=Capped Collection(有限集合)

1.2 集合

集合(set)類型也是用來保存多個的字符串元素,但和列表不一樣的是:它的元素是無序且不可重複的,不能經過索引獲取元素.以下圖,集合user:1:follows中包含着"his"、"it"、"sports"、"music"四個元素,一個集合最多能夠存儲(2的32次方-1)個元素.
clipboard.png

1.2.1 命令

1) 集合內操做

(1) 添加元素

sadd key value [value...]

返回結果爲添加成功的元素數量.
例:

添加元素

(2) 刪除元素

srem key value [value...]

返回結果爲刪除成功的元素數量.
例:

刪除元素

(3) 獲取元素個數

scard key

例:

獲取元素個數

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

sismember key value

若是元素存在於集合內則返回1,反之返回0.
例:

判斷元素是否在集合中

(5) 隨機從集合中返回指定個數元素

srandmember key [count]

[count]是可選參數,若是不寫默認爲:1.
例:

隨機從集合中返回指定個數元素

(6) 從集合中隨機彈出元素

spop key

spop操做能夠從集合中隨機彈出一個元素.

例:
從集合中隨機彈出元素
使用spop命令後,集合元素變爲"1","3".

(7) 獲取集合的全部元素

smembers key

獲取集合全部元素,且返回結果是無序的.

獲取集合的全部元素

2) 集合間操做

(1) 求多個集合的交集

sinter key [key...]

例:

求多個集合的交集

(2) 求多個集合的並集

sunion key [key...]

例:

求多個集合的並集

(3) 求多個集合的差集

sdiff key [key...]

例:

求多個集合的差集

(4) 將交集、並集、差集的結果保存.

sinterstore storeKey key [key...]
    sunionstore storeKey key [key...]
    sdiffstore storeKey key [key...]

集合間的運算在元素比較多的狀況下會比較耗時,因此redis提供了上面三個命令(原命令+store)將集合間交集、並集、差集的結果保存到storeKey中,例如將user:1:followsuser:2:follows兩個集合之間的交集結果保存到user:1_2:follows中.
交集保存

1.2.2 內部編碼

集合類型的內部編碼有兩種:

編碼名 編碼描述
intset(整數集合) 當集合中的元素全是整數,且長度不超過set-max-intset-entries(默認爲512個)時,redis會選用intset做爲內部編碼.
hashtable(哈希表) 當集合沒法知足intset的條件時,redis會使用hashtable做爲內部編碼.

1.2.3 使用場景

集合類型比較典型的使用場景是標籤(tag).例如一個用戶可能對音樂感興趣,另外一個用戶對新聞感興趣,這些想去點就是標籤.有了這些數據就能夠得到喜歡同一個標籤的人,以及用戶的共同喜愛的標籤,這些數據對於用戶體驗來講比較重要.

下面使用集合類型實現標籤功能的若干功能.例如:

(1) 給用戶添加標籤:
給用戶添加標籤

(2) 給標籤添加用戶:
給標籤添加用戶

(3) 刪除用戶的標籤:
刪除用戶的標籤

(4) 刪除標籤的用戶:
刪除標籤的用戶
34最好在同一個事務下進行處理.

(5) 計算用戶共同擁有的標籤:
clipboard.png

1.3 有序集合

有序集合相對於哈希、列表、集合來講會有一點陌生,但既然叫有序集合.那麼它和集合必然是有着聯繫,它保留了集合不能重複元素的特性.但不一樣的是,有序集合是可排序的.可是他和列表使用索引下標進行排序依據不一樣的是,它給每一個元素設置一個分數(score)做爲排序的依據.
clipboard.png

列表、集合、有序結合的異同點

數據結構 是否容許重複元素 是否有序 有序實現方式 應用場景
集合 標籤、社交等.
有序集合 分值 排行榜、社交等.
列表 索引下標 時間軸、消息隊列等.

1.3.1 命令

1)集合內

(1) 添加成員

zadd key score member [score member ...]

下面操做向有序集合user:ranking增長用戶Rico和他的分數60分:

添加成員

有關zadd命令有兩點須要注意:

  • Redis 3.2zadd命令添加了nxxxchincr四個選項:

    • nx:member必須不存在,才能夠設置成功,用於添加.

    • xx:member必須存在,才能夠設置成功,用於添加.

    • ch:返回這次操做後,有序結合元素和分數發生變化的個數.

    • incr: 對score進行添加操做,至關於後面介紹的zincrby.

  • 有序集合相比集合提供了排序字段,可是也產生了代價,zadd的時間複雜度是O(log(n)),sadd的時間複雜度爲O(1).

(2) 獲取成員個數

zcard key

例:
clipboard.png

(3) 獲取某個成員的分數

zscore key member

例:
獲取某個成員的分數

(4) 獲取成員排名

zrank key member
    zrevrank key member

zrank命令是從分數從低到高返回排名,zrevrank反之,排名從0開始.例以下面:

計算成員的排名

(5) 刪除成員

zrem key member [member...]

下面操做成員ann從有序集合user:ranking中刪除.

刪除成員

(6) 增長成員分數

zincrby key score member

下面操做給Rico成員添加9分,分數變爲69分.

增長成員分數

(7) 獲取制定範圍的元素

zrange key start end [withscores] 
    zrevrange key start end [withscores]

有序集合是按照分值排名的,zrange是由低到高返回,zrevrange反之,查詢所有:zrange user:ranking 0 -1,加上withscores參數顯示分數.
例:
獲取前三名.

127.0.0.1:6379> zrange user:ranking 0 2
    1) "codger"
    2) "hank"
    3) "ann"
    127.0.0.1:6379> zrevrange user:ranking 0 2
    1) "tom"
    2) "Rico"
    3) "ann"

(8) 返回指定分數範圍的成員

zrangebyscore key min max [withscores] [limit offset count]
    
    zrevrangebyscore key min max [withscores] [limit offset count]

例:
返回分數在0100的成員.

127.0.0.1:6379> zrangebyscore user:ranking 0 100
    1) "codger"
    2) "hank"
    3) "ann"
    4) "Rico"
    5) "tom"

返回分數在0到無限大的成員.

127.0.0.1:6379> zrangebyscore user:ranking 0 +inf
    1) "codger"
    2) "hank"
    3) "ann"
    4) "Rico"
    5) "tom"

同時minmax還支持開區間(小括號)和閉區間(中括號),-inf+inf分別表明無限小和無限大:

127.0.0.1:6379> zrangebyscore user:ranking (10 +inf withscores
    1) "hank"
    2) "15"
    3) "ann"
    4) "30"
    5) "Rico"
    6) "69"
    7) "tom"
    8) "80"

(9) 返回指定分數範圍成員個數

zcount key min max

下面返回分數爲1015的成員:

127.0.0.1:6379> zcount user:ranking (10 15
    (integer) 1

(10) 刪除指定排名內的升序元素

zremrangebyrank key start end

刪除第start到第end名的成員:

127.0.0.1:6379> zremrangebyrank user:ranking 0 1
    (integer) 2

(11) 刪除指定分數範圍的成員

zremrangebyscore key min max

刪除分數從minmax的成員:

127.0.0.1:6379> zremrangebyscore user:ranking 0 30
    (integer) 1

2) 集合間的操做

(1) 交集

zinterstore storeKey keyNum key [key ...] [weights weight [weight...]] [aggregate sum|min|max]

參數說明:

  • storeKey:交集計算結果保存到這個鍵下.

  • keyNum:須要作交集的鍵的個數.

  • key[key ...]:須要作交集的鍵.

  • weights weight [weight...]:每一個鍵的權重,在作交集計算時,每一個鍵中的每一個member的分值會和這個權重相乘,每一個鍵的權重默認爲1.

  • aggregate sum|min|sum:計算成員交集後,分值能夠按照sum(和)、min(最小值)、max(最大值)作彙總.默認值爲sum.

127.0.0.1:6379> zrange user:ranking:2 0 -1 withscores
    1) "Rico"
    2) "138"
    3) "tom"
    4) "160"
    127.0.0.1:6379> zinterstore user:ranking:1_2 2 user:ranking user:ranking:2 aggregate min
    (integer) 2
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1
    1) "Rico"
    2) "tom"
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1 withscores
    1) "Rico"
    2) "69"
    3) "tom"
    4) "80"

(2) 並集

zunionstore storeKey keyNum key [key...] [weights weight [weight...]] [aggregate sum|min|max]

該命令的全部參數和zinterstore是一致的,只不過作的是並集計算.
例:

127.0.0.1:6379> zunionstore user:ranking:1_2 2 user:ranking user:ranking:2  aggregate min
    (integer) 3
    127.0.0.1:6379> zrange user:ranking:1_2 0 -1 withscores
    1) "Rico"
    2) "69"
    3) "codger"
    4) "90"
    5) "tom"
    6) "160"

1.3.2 內部編碼

編碼名稱 編碼描述
ziplist(壓縮列表) 當有序集合的元素小於zset-max-ziplist-entries配置(默認是128個),同時每一個元素的值都小於zset-max-ziplist-value(默認是64字節)時,Redis會用ziplist來做爲有序集合的內部編碼實現,ziplist能夠有效的減小內存的使用
skiplist(跳躍表) ziplist的條件不知足時,有序集合將使用skiplist做爲內部編碼的實現,來解決此時ziplist形成的讀寫效率降低的問題.
相關文章
相關標籤/搜索