一、前言
Redis 提供了 5 种数据类型:String(字符串)、Hash(哈希)、List(列表)、Set(汇合)、Zset(有序汇合),了解每种数据类型的特点对于 redis 的开发和运维十分重要。
<p align=”right”> 原文解析 </p>
Redis 中的 Set 是咱们常常应用到的一种数据类型,依据应用形式的不同,能够利用到很多场景中。
二、底层实现
汇合对象的编码能够是 intset 或者 hashtable。
intset 编码的汇合对象应用整数汇合作为底层实现,汇合对象蕴含的所有元素都被保留在整数汇合外面。
举个例子,以下代码将创立一个如图 8-12 所示的 intset 编码汇合对象:
redis> SADD numbers 1 3 5
(integer) 3
结构图 8-12:
另一方面,hashtable 编码的汇合对象应用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象蕴含了一个汇合元素,而字典的值则全副被设置为 NULL。
举个例子,以下代码将创立一个如图 8-13 所示的 hashtable 编码汇合对象:
redis> SADD fruits "apple" "banana" "cherry"
(integer) 3
结构图 8-13:
三、编码转换
当汇合对象能够同时满足以下两个条件时,对象应用 intset 编码:
1. 汇合对象保留的所有元素都是整数值;
2. 汇合对象保留的元素数量不超过 512 个;
不能满足这两个条件的汇合对象须要应用 hashtable 编码。
留神 : 第二个条件的上限值是能够批改的,具体请看配置文件中对于 set-max-intset-entries 选项的阐明。对于应用 intset 编码的汇合对象来说,当应用 intset 编码所需的两个条件的任意一个不能被满足时,对象的编码转换操作就会被执行:本来保留在整数汇合中的所有元素都会被转移并保留到字典外面,并且对象的编码也会从 intset 变为 hashtable。
举个例子,以下代码创立了一个只蕴含整数元素的汇合对象,该对象的编码为 intset:
redis> SADD numbers 1 3 5
(integer) 3
redis> OBJECT ENCODING numbers
"intset"
不过,只有咱们向这个只蕴含整数元素的汇合对象增加一个字符串元素,汇合对象的编码转移操作就会被执行
redis> SADD numbers "seven"
(integer) 1
redis> OBJECT ENCODING numbers
"hashtable"
除此之外,如果咱们创立一个蕴含 512 个整数元素的汇合对象,那么对象的编码应该会是 intset:
redis> EVAL "for i=1, 512 do redis.call('SADD', KEYS[1], i) end" 1 integers
(nil)
redis> SCARD integers
(integer) 512
redis> OBJECT ENCODING integers
"intset"
然而,只有咱们再向汇合增加一个新的整数元素,使得这个汇合的元素数量变成 513,那么对象的编码转换操作就会被执行:
redis> SADD integers 10086
(integer) 1
redis> SCARD integers
(integer) 513
redis> OBJECT ENCODING integers
"hashtable"
四、命令实现
因为汇合键的值为汇合对象,所以用于汇合键的所有命令都是针对汇合对象来构建的,以下表格列出了其中一部分汇合键命令,以及这些命令在不同编码的汇合对象下的实现办法。
命令 | intset 编码的实现办法 | hashtable 编码的实现办法 |
---|---|---|
SADD | 调用 intsetAdd 函数,将所有新元素增加到整数汇合外面。 | 调用 dictAdd,以新元素为键,NULL 为值,将键值对增加到字典外面。 |
SCARD | 调用 intsetLen 函数,返回整数汇合所蕴含的元素数量,这个数量就是汇合对象所蕴含的元素数量。 | 调用 dictSize 函数,返回字典所蕴含的键值对数量,这个数量就是汇合对象所蕴含的元素数量。 |
SISMEMBER | 调用 intsetFind 函数,在整数汇合中查找给定的元素,如果找到了阐明元素存在于汇合,没找到则阐明元素不存在于汇合。 | 调用 dictFind 函数,在字典的键中查找给定的元素,如果找到了阐明元素存在于汇合,没找到则阐明元素不存在于汇合。 |
SMEMBERS | 遍历整个整数汇合,应用 intsetGet 函数返回汇合元素。 | 遍历整个字典,应用 dictGetKey 函数返回字典的键作为汇合元素。 |
SRANDMEMBER | 调用 intsetRandom 函数,从整数汇合中随机返回一个元素。 | 调用 dictGetRandomKey 函数,从字典中随机返回一个字典键。 |
SPOP | 调用 intsetRandom 函数,从整数汇合中随机取出一个元素,在将这个随机元素返回给客户端之后,调用 intsetRemove 函数,将随机元素从整数汇合中删除掉。 | 调用 dictGetRandomKey 函数,从字典中随机取出一个字典键,在将这个随机字典键的值返回给客户端之后,调用 dictDelete 函数,从字典中删除随机字典键所对应的键值对。 |
SREM | 调用 intsetRemove 函数,从整数汇合中删除所有给定的元素。 | 调用 dictDelete 函数,从字典中删除所有键为给定元素的键值对。 |
五、利用场景
1. 抽奖
抽奖
1)用户参加抽奖:SADD order 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
2)查看所有参加抽奖的人:SMEMBERS order
3)反复抽奖每次抽取两人:SMEMBERS order 2
4)不反复抽奖,三等奖 3 人,二等奖 2 人,一等奖 1 人
SPOP order 3
SPOP order 2
SPOP order 1
2. 点赞、珍藏、标签
点赞、珍藏、标签
1)点赞的人:SADD like:1 1001 1002 1003 1004 1005
2)勾销点赞:SREM like:1 1002
3)检查用户是否点赞过:SISMEMBER like:1 1002
SISMEMBER like:1 1005
4)获取点赞人员列表:SMEMBERS like:1
5)获取点赞总人数:SCARD like:1
3. 关注模型
redis> SADD wangwu zhangsan lisi zhaoliu haoba
(integer) 4
redis> SADD zhangsan lisi wangwu sijiu
(integer) 3
redis> SADD lisi zhaoliu zhangsan qinshi
(integer) 3
redis> SINTER wangwu zhangsan
1) "lisi"
redis> SISMEMBER zhangsan lisi
(integer) 1
redis> SISMEMBER lisi zhangsan
(integer) 1
redis> SISMEMBER zhaoliu zhangsan
(integer) 0
redis> SISMEMBER haoba zhangsan
(integer) 0
redis> SDIFF zhangsan wangwu
1) "sijiu"
2) "wangwu"
redis> SDIFF lisi wangwu
1) "qinshi"
六、要点总结
(1)汇合对象的编码能够是 intset 或者 hashtable。
(2)intset 编码的汇合对象应用整数汇合作为底层实现。
(3)hashtable 编码的汇合对象应用字典作为底层实现。
(4)intset 与 hashtable 编码之间,符合条件的状况下,能够转换。
over