天天看點

Redis實戰之集合與有序集合(類型的實作、操作與常用場景)

集合

集合(set)類型也是用來儲存多個的字元串元素,但和清單類型不一樣的是,集合中不允許有重複元素,并且集合中的元素是無序的,不能通過索引下标擷取元素。如圖2-22所示,集合user:1:follow包含着"it"、"music"、"his"、"sports"四個元素,一個集合最多可以存儲232-1個元素。Redis除了支援集合内的增删改查,同時還支援多個集合取交集、并集、差集,合理地使用好集合類型,能在實際開發中解決很多實際問題。

指令

1.集合内操作

1.sadd key element [element ...]    添加元素,傳回結果為添加成功的元素個數    sadd myset a b c

2.srem key element [element ...]    删除元素,傳回結果為成功删除元素個數        srem myset a b

3.scard key    計算元素個數,scard的時間複雜度為O(1),它不會周遊集合所有元素,而是直接用 Redis内部的變量。

4.sismember key element     判斷元素是否在集合中,如果給定元素element在集合内傳回1,反之傳回0    sismember myset c

5.srandmember key [count]     随機從集合傳回指定個數元素    srandmember myset 2

6.spop key   從集合随機彈出元素   spop myset srandmember和spop都是随機從集合選出元素,兩者不同的是spop指令執行後,元素會從集合中删除,而 srandmember不會

7.smembers key    擷取所有元素    smembers和lrange、hgetall都屬于比較重的指令,如果元素過多存在阻塞 Redis的可能性,這時候可以使用sscan來完成 smembers myset

2.集合間操作

1.sinter key [key ...]    求多個集合的交集,下面代碼是求user:1:follow和user:2:follow兩個集合的交集,傳回結果是sports、it sinter user:1:follow user:2:follow

2.suinon key [key ...] 求多個集合的并集

3.sdiff key [key ...] 求多個集合的差集

4.sinterstore destination key [key ...] 将交集、并集、差集的結果儲存    suionstore destination key [key ...] sdiffstore destination key [key ...] 集合間的運算在元素較多的情況下會比較耗時,是以Redis提供了上面三個指令(原指令+store)将集合間交 集、并集、差集的結果儲存在destination key中

内部編碼

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

intset(整數集合):當集合中的元素都是整數且元素個數小于set-maxintset-entries配置(預設512個)時,Redis會選用intset來作為集合的内部實作,進而減少記憶體的使用。

hashtable(哈希表):當集合類型無法滿足intset的條件時,Redis會使用hashtable作為集合的内部實作。

使用場景

集合類型比較典型的使用場景是标簽(tag)。例如一個使用者可能對娛樂、體育比較感興趣,另一個使用者可能對曆史、新聞比較感興趣,這些興趣點就是标簽。有了這些資料就可以得到喜歡同一個标簽的人,以及使用者的共同喜好的标簽,這些資料對于使用者體驗以及增強使用者黏度比較重要。例如一個電子商務的網站會對不同标簽的使用者做不同類型的推薦,比如對數位産品比較感興趣的人,在各個頁面或者通過郵件的形式給他們推薦最新的數位産品,通常會為網站帶來更多的利益。

1.給使用者添加标簽

sadd user:1:tags tag1 tag2 tag5 ​ sadd user:2:tags tag2 tag3 tag5

2.給标簽添加使用者

sadd tag1:users user:1 user:3 ​ sadd tag2:users user:1 user:2 user:3

3.删除使用者下的标簽

​ srem user:1:tags tag1 tag5

4.删除标簽下的使用者

​ srem tag1:users user:1 srem

5.計算使用者共同感興趣的标簽

有序集合

有序集合相對于哈希、清單、集合來說會有一點點陌生,但既然叫有序集合,那麼它和集合必然有着聯系,它保留了集合不能有重複成員的特性,但不同的是,有序集合中的元素可以排序。但是它和清單使用索引下标作為排序依據不同的是,它給每個元素設定一個分數(score)作為排序的依據。如圖2-24所示,該有序集合包含kris、mike、frank、tim、martin、tom,它們的分數分别1、91、200、220、250、251,有序集合提供了擷取指定分數和元素範圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題

Redis實戰之集合與有序集合(類型的實作、操作與常用場景)
Redis實戰之集合與有序集合(類型的實作、操作與常用場景)

1.集合内

1.zadd key score member [score member ...] 添加成員,傳回結果代表成功添加成員的個數

127.0.0.1:6379> zadd user:ranking 1 kris 91 mike 200 frank 220 tim 250 martin

(integer) 5

Redis3.2為zadd指令添加了nx、xx、ch、incr四個選項:

·nx:member必須不存在,才可以設定成功,用于添加。

·xx:member必須存在,才可以設定成功,用于更新。

·ch:傳回此次操作後,有序集合元素和分數發生變化的個數

·incr:對score做增加,相當于後面介紹的zincrby。

·有序集合相比集合提供了排序字段,但是也産生了代價,zadd的時間複雜度為O(log(n)),sadd的時間 複雜度為O(1)。

2.zcard key 計算成員個數。

傳回有序集合user:ranking的成員數為5,和集合類型的 scard指令一樣,zcard的時間複雜度為O(1)

3.zscore key member 計算某個成員的分數。 zscore user:ranking tom "251"

4.zrank key member zrevrank 計算成員的排名,zrank是從分數從低到高傳回排名,zrevrank反之。例如 下面操作中,tom 在zrank和zrevrank分别排名第5和第0(排名從0開始計算)

5.zrem key member [member ...] 删除成員 zrem user:ranking mike 操作将成員mike從有序集合user:ranking中删除

6.zincrby key increment member 增加成員的分數.

Redis實戰之集合與有序集合(類型的實作、操作與常用場景)

内部編碼

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

·ziplist(壓縮清單):當有序集合的元素個數小于zset-max-ziplistentries配置(預設128個),同時每個元素的值都小于zset-max-ziplist-value配置(預設64位元組)時,Redis會用ziplist來作為有序集合的内部實作,ziplist

可以有效減少記憶體的使用。

·skiplist(跳躍表):當ziplist條件不滿足時,有序集合會使用skiplist作

為内部實作,因為此時ziplist的讀寫效率會下降。

Redis實戰之集合與有序集合(類型的實作、操作與常用場景)

使用場景

有序集合比較典型的使用場景就是排行榜系統。例如視訊網站需要對使用者上傳的視訊做排行榜,榜單的次元可能是多個方面的:按照時間、按照播放數量、按照獲得的贊數。本節使用贊數這個次元,記錄每天使用者上傳視訊的排行榜。主要需要實作以下4個功能。

1.添加使用者贊數

例如使用者mike上傳了一個視訊,并獲得了3個贊,可以使用有序集合的 zadd和zincrby功能: ​

zadd user:ranking:2016_03_15 mike 3 如果之後再獲得一個贊,可以使用zincrby: ​

zincrby user:ranking:2016_03_15 mike 1

2取消使用者贊數

由于各種原因(例如使用者登出、使用者作弊)需要将使用者删除,此時需要将使用者從榜單中删除掉,可以使用zrem。例如删除成員tom:

zrem user:ranking:2016_03_15 mike

3.展示擷取贊數最多的十個使用者

此功能使用zrevrange指令實作: zrevrangebyrank user:ranking:2016_03_15 0 9

4.展示使用者資訊以及使用者分數

此功能将使用者名作為鍵字尾,将使用者資訊儲存在哈希類型中,至于使用者

的分數和排名可以使用zscore和zrank兩個功能:

hgetall user:info:tom zscore user:ranking:2016_03_15 mike zrank user:ranking:2016_03_15 mike

繼續閱讀