一、前言
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) 3redis> OBJECT ENCODING numbers"intset"
不过, 只有咱们向这个只蕴含整数元素的汇合对象增加一个字符串元素,汇合对象的编码转移操作就会被执行
redis> SADD numbers "seven"(integer) 1redis> 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) 512redis> OBJECT ENCODING integers"intset"
然而, 只有咱们再向汇合增加一个新的整数元素, 使得这个汇合的元素数量变成 513 , 那么对象的编码转换操作就会被执行:
redis> SADD integers 10086(integer) 1redis> SCARD integers(integer) 513redis> 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) 4redis> SADD zhangsan lisi wangwu sijiu (integer) 3redis> SADD lisi zhaoliu zhangsan qinshi (integer) 3redis> SINTER wangwu zhangsan 1) "lisi"redis> SISMEMBER zhangsan lisi (integer) 1redis> SISMEMBER lisi zhangsan (integer) 1redis> SISMEMBER zhaoliu zhangsan (integer) 0redis> SISMEMBER haoba zhangsan (integer) 0redis> SDIFF zhangsan wangwu 1) "sijiu" 2) "wangwu"redis> SDIFF lisi wangwu 1) "qinshi"
六、要点总结
(1)汇合对象的编码能够是 intset 或者 hashtable 。(2)intset 编码的汇合对象应用整数汇合作为底层实现。
(3)hashtable 编码的汇合对象应用字典作为底层实现。
(4)intset 与 hashtable 编码之间,符合条件的状况下,能够转换。
over