一、操作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出一个元素,可以作为抽奖的号码
- 交集、并集、差集 可以用来作为社交的探索,最大的例子就是微博了,开发共同关注、共同喜好、二度好友等功能