一、操作Set(集合對象)類型
常言道:神龍生九子,九子各不同,對於Redis來說Set也是其得力的“干將”,Set集合也是用來保存多個字符串,和平常的Set一樣是無序,無重複元素的,所以不能像List集合那樣通過索引下標來獲取元素,而是直接獲取全部元素,或者隨機獲取到某一個元素。但是對於Set集合來說更多的優點在於可以求交集、並集、差集這就是其重要的屬性,接着一起來看看怎麼操作吧👇:
private void setSetValue(String key){
//向sets集合中加入元素, 成功返回1, 失敗返回0
//sadd key element ...
getJedis().sadd(key,"setValue");
Long sadd = getJedis().sadd(key, "setValue1", "setValue2", "setValue3", "setValue4");
//獲取所有元素 smembers key
Set<String> set = getJedis().smembers(key);
//刪除元素 srem key element [element ...]
Long srem = getJedis().srem(key, "setValue4");
//是否存在這個元素 sismember key element
Boolean sismember = getJedis().sismember(key, "setValue5");
//統計元素個數 scrad key
Long scard = getJedis().scard(key);
// 隨機獲取一個元素,或者指定返回幾個 srandmember key [count]
String srandmember = getJedis().srandmember(key);
List<String> srandmember1 = getJedis().srandmember(key, 4);
//從集合隨機彈出元素 spop key
String spop = getJedis().spop(key);
//或者指定彈出 集合裏面 那幾個元素
getJedis().spop(key,1);
getJedis().sadd("fruit", "apple", "banana", "orange", "grape");
getJedis().sadd("food", "orange", "grape", "peach", "lemon");
// 求交集 sinter key [key ...]
Set<String> setsinter = getJedis().sinter("fruit", "food");
// 求交集並存儲到指定集合
getJedis().sinterstore("sinter", "fruit", "food");
// 求並集 suinon key [key ...]
Set<String> sunion = getJedis().sunion("fruit", "food");
//將所得並集存儲到指定集合
getJedis().sunionstore("newSet","fruit","food");
// 求差集(fruit中有, food中沒有的元素) sdiff key [key ...]
Set<String> sdiff = getJedis().sdiff("fruit", "food");
//求差集並存儲到指定集合
Long sdiffstore = getJedis().sdiffstore("newKey", "fruit", "food");
}
二、有關Redis的Set(集合對象)編碼
1、有關集合對象Set的編碼
set集合對象有兩種編碼:intset和hashtable,在不同類型和編碼的對象裏面指出了Set對象的編碼:
#使用整數集合實現的集合對象。
REDIS_SET REDIS_ENCODING_INTSET
#使用字典實現的集合對象。
REDIS_SET REDIS_ENCODING_HT
intset是一個整數集合,裏面存的爲某種同一類型的整數,支持如下三種長度的整數:
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
intset是一個有序集合,查找元素的複雜度爲O(logN),但插入時不一定爲O(logN),因爲有可能涉及到升級操作。比如當集合裏全是int16_t型的整數,這時要插入一個int32_t,那麼爲了維持集合中數據類型的一致,那麼所有的數據都會被轉換成int32_t類型,涉及到內存的重新分配,這時插入的複雜度就爲O(N)了。 intset不支持降級操作。
OBJECT ENCODING 對不同編碼的輸出,intset和ht分別對應了
整數集合 REDIS_ENCODING_INTSET "intset"
字典 REDIS_ENCODING_HT "hashtable"
那什麼情況下會使用intset,什麼情況下才開始使用hashtable呢?intset這個屬性要符合兩個
- 所有元素都是整數值
- 元素數量不超過512個
當然這個數字是可以在Redis配置文件裏面設置set-max-intset-entries 的值來指定的。
2、補充字典的一些事情
字典是一種用來保存鍵值對的抽象數據結構,爲什麼抽象呢,這是連C語言都沒有的數據結構,是Redis自己實現的,通過key-value的形式,每一個鍵都是唯一的來關聯一個Value,被稱爲關聯數組(associative array),映射(map),符號表。符號表是指一種存儲鍵值對的數據結構,支持兩種操作:插入(put)
,即將一組新的鍵值對存入表中;查找(get)
,即根據給定的鍵得到相應的值,所以字典被稱爲符號表(symbol table)。
Redis 字典所使用的哈希表由 dict.h/dictht 結構定義,這些都是在使用hash對象的時候有講解過的,就不累贅了(☄⊙ω⊙)☄:【Redis 三】Jedis操作Redis的Hash類型
set集合對象使用HashTable編碼,其中所有的鍵都是字符串對象,每個字符串對象都包含一個集合,每個字符串對象的值爲null,也就是set 的內部實現是一個 value永遠爲null的HashMap。讓我們來回顧一下,set集合對象無序,最大可以存儲2^32-1 個字節,又因爲是HashTable實現的,所以增、刪、改 都是O(N)的,而HashTable的增刪是自動擴展/壓縮內存空間的,哪怕hashTable調整大小需要同步(獲取寫鎖)會阻塞其他讀寫操作,所以set集合對象有自動調節大小這個特性,也有調整大小的時候會阻塞其他讀寫的問題。
三、set對象集合的使用場景
根據第一點的各種操作我們可以利用其特性來做一些比較特別的事情
- 去重 redis的set去重可以被用來作爲各種標籤
- 隨機數 利用可以不重複且可以取出隨機數,可用作類似 抽獎 隨機pop出一個元素,可以作爲抽獎的號碼
- 交集、並集、差集 可以用來作爲社交的探索,最大的例子就是微博了,開發共同關注、共同喜好、二度好友等功能