Redis物件——集合(Set)
集合型別 (Set) 是一個無序並唯一的鍵值集合。它的儲存順序不會按照插入的先後順序進行儲存。
集合型別和列表型別的區別如下:
- 列表可以儲存重複元素,集合只能儲存非重複元素;
- 列表是按照元素的先後順序儲存元素的,而集合則是無序方式儲存元素的。
一個集合最多可以儲存232-1個元素。Redis除了支援集合內的增刪改查,同時還支援多個集合取交集、並集、差集,合理地使用好集合型別,能在實際開發中解決很多實際問題。
一、內部實現
集合型別的內部編碼有兩種:
-
intset(整數集合):當集合中的元素都是整數且元素個數小於set-maxintset-entries配置(預設512個)時,Redis會選用intset來作為集合的內部實現,從而減少記憶體的使用。
-
hashtable(雜湊表):當集合型別無法滿足intset的條件時,Redis會使用hashtable作為集合的內部實現。
有關intset和hashtable這兩種redis底層資料結構的具體實現可以參考我的另外兩篇文章。
Redis資料結構——整數集合
Redis資料結構——字典。
二、常用命令
Redis列表物件常用命令如下表(點選命令可檢視命令詳細說明)。
命令 | 說明 | 時間複雜度 |
---|---|---|
SADD key member [member ...] | 新增一個或者多個元素到集合(set)裡 | O(N) |
SCARD key | 獲取集合裡面的元素數量 | O(1) |
SDIFF key [key ...] | 獲得佇列不存在的元素 | O(N) |
SDIFFSTORE destination key [key ...] | 獲得佇列不存在的元素,並存儲在一個關鍵的結果集 | O(N) |
SINTER key [key ...] | 獲得兩個集合的交集 | O(N*M) |
SINTERSTORE destination key [key ...] | 獲得兩個集合的交集,並存儲在一個關鍵的結果集 | O(N*M) |
SISMEMBER key member | 確定一個給定的值是一個集合的成員 | O(1) |
SMEMBERS key | 獲取集合裡面的所有元素 | O(N) |
SMOVE source destination member | 移動集合裡面的一個元素到另一個集合 | O(1) |
SPOP key [count] | 刪除並獲取一個集合裡面的元素 | O(1) |
SRANDMEMBER key [count] | 從集合裡面隨機獲取一個元素 | |
SREM key member [member ...] | 從集合裡刪除一個或多個元素 | O(N) |
SUNION key [key ...] | 新增多個set元素 | O(N) |
SUNIONSTORE destination key [key ...] | 合併set元素,並將結果存入新的set裡面 | O(N) |
SSCAN key cursor [MATCH pattern] [COUNT count] | 迭代set裡面的元素 | O(1) |
三、使用場景
通過上文,我們可以知道集合的主要幾個特性,無序、不可重複、支援並交差等操作。因此集合型別比較適合用來資料去重和保障資料的唯一性,還可以用來統計多個集合的交集、錯集和並集等,當我們儲存的資料是無序並且需要去重的情況下,比較適合使用集合型別進行儲存。
3.1 標籤系統
集合型別比較典型的使用場景是標籤(tag)。
-
給使用者新增標籤。
sadd user:1:tags tag1 tag2 tag5 sadd user:2:tags tag2 tag3 tag5 ... sadd user:k:tags tag1 tag2 tag4 ...
-
給標籤新增使用者
sadd tag1:users user:1 user:3 sadd tag2:users user:1 user:2 user:3 ... sadd tagk:users user:1 user:2 ...
-
使用sinter命令,可以來計算使用者共同感興趣的標籤
sinter user:1:tags user:2:tags
這種標籤系統在電商系統、社交系統、視訊網站,圖書網站,旅遊網站等都有著廣泛的應用。例如一個使用者可能對娛樂、體育比較感興趣,另一個使用者可能對歷史、新聞比較感興趣,這些興趣點就是標籤。有了這些資料就可以得到喜歡同一個標籤的人,以及使用者的共同喜好的標籤,這些資料對於使用者體驗以及增強使用者黏度比較重要。例如一個社交系統可以根據使用者的標籤進行好友的推薦,已經使用者感興趣的新聞的推薦等,一個電子商務的網站會對不同標籤的使用者做不同型別的推薦,比如對數碼產品比較感興趣的人,在各個頁面或者通過郵件的形式給他們推薦最新的數碼產品,通常會為網站帶來更多的利益。
3.2 抽獎系統
Redis集合的 SPOP(隨機移除並返回集合中一個或多個元素) 和 SRANDMEMBER(隨機返回集合中一個或多個元素) 命令可以幫助我們實現一個抽獎系統
如果允許重複中獎,可以使用SRANDMEMBER 命令
//新增抽獎名單
127.0.0.1:6379> SADD lucky:1 Tom
(integer) 1
127.0.0.1:6379> SADD lucky:1 Jerry
(integer) 1
127.0.0.1:6379> SADD lucky:1 John
(integer) 1
127.0.0.1:6379> SADD lucky:1 Marry
(integer) 1
127.0.0.1:6379> SADD lucky:1 Sean
(integer) 1
127.0.0.1:6379> SADD lucky:1 Lindy
(integer) 1
127.0.0.1:6379> SADD lucky:1 Echo
(integer) 1
//抽取三等獎3個
127.0.0.1:6379> SRANDMEMBER lucky:1 3
1) "John"
2) "Echo"
3) "Lindy"
//抽取二等獎2個
127.0.0.1:6379> SRANDMEMBER lucky:1 2
1) "Sean"
2) "Lindy"
//抽取一等獎1個
127.0.0.1:6379> SRANDMEMBER lucky:1 1
1) "Tom"
如果不允許重複中獎,可以使用 SPOP 命令
//新增抽獎名單
127.0.0.1:6379> SADD lucky:1 Tom
(integer) 1
127.0.0.1:6379> SADD lucky:1 Jerry
(integer) 1
127.0.0.1:6379> SADD lucky:1 John
(integer) 1
127.0.0.1:6379> SADD lucky:1 Marry
(integer) 1
127.0.0.1:6379> SADD lucky:1 Sean
(integer) 1
127.0.0.1:6379> SADD lucky:1 Lindy
(integer) 1
127.0.0.1:6379> SADD lucky:1 Echo
(integer) 1
//抽取三等獎3個
127.0.0.1:6379> SPOP lucky:1 3
1) "John"
2) "Echo"
3) "Lindy"
//抽取二等獎2個
127.0.0.1:6379> SPOP lucky:1 2
1) "Sean"
2) "Marry"
//抽取一等獎1個
127.0.0.1:6379> SPOP lucky:1 1
1) "Tom"
注意:
Redis 2.6版本開始SRANDMEMBER命令支援Count引數。
Redis 3.2版本開始SRANDMEMBER命令支援Count引數。
其餘低版本一次只能獲取一個隨機元素。
小結
本篇文章我們總結了Redis 集合物件的內部實現、常用命令以及常用的一些場景,那麼大家在專案中對Redis集合物件的使用都有哪些場景呢,歡迎在評論區給我留言和分享,我會第一時間反饋!我們共同學習與進步!
參考
《Redis設計與實現》
《Redis開發與運維》
《Redis官方文件》