集合
集合(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,有序集合提供了擷取指定分數和元素範圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題
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 增加成員的分數.
内部編碼
有序集合類型的内部編碼有兩種:
·ziplist(壓縮清單):當有序集合的元素個數小于zset-max-ziplistentries配置(預設128個),同時每個元素的值都小于zset-max-ziplist-value配置(預設64位元組)時,Redis會用ziplist來作為有序集合的内部實作,ziplist
可以有效減少記憶體的使用。
·skiplist(跳躍表):當ziplist條件不滿足時,有序集合會使用skiplist作
為内部實作,因為此時ziplist的讀寫效率會下降。
使用場景
有序集合比較典型的使用場景就是排行榜系統。例如視訊網站需要對使用者上傳的視訊做排行榜,榜單的次元可能是多個方面的:按照時間、按照播放數量、按照獲得的贊數。本節使用贊數這個次元,記錄每天使用者上傳視訊的排行榜。主要需要實作以下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