集合对象¶
集合对象的编码可以是 intset
或者 hashtable
。
intset
编码的集合对象使用整数集合作为底层实现,
集合对象包含的所有元素都被保存在整数集合里面。
举个例子,
以下代码将创建一个如图 8-12 所示的 intset
编码集合对象:
redis> SADD numbers 1 3 5
(integer) 3
![digraph {
label = "\n 图 8-12 intset 编码的 numbers 集合对象";
rankdir = LR;
node [shape = record];
redisObject [label = " redisObject | type \n REDIS_SET | encoding \n REDIS_ENCODING_INTSET | <ptr> ptr | ... "];
intset [label = " <head> intset | encoding \n INTSET_ENC_INT16 | length \n 3 | <contents> contents "];
contents [label = " { 1 | 3 | 5 } "];
redisObject:ptr -> intset:head;
intset:contents -> contents;
}](../../_images/graphviz-5cf6b331e56c044dc40cf66aa3191b48588b027f.png)
另一方面,
hashtable
编码的集合对象使用字典作为底层实现,
字典的每个键都是一个字符串对象,
每个字符串对象包含了一个集合元素,
而字典的值则全部被设置为 NULL
。
举个例子,
以下代码将创建一个如图 8-13 所示的 hashtable
编码集合对象:
redis> SADD fruits "apple" "banana" "cherry"
(integer) 3
![digraph {
label = "\n 图 8-13 hashtable 编码的 fruits 集合对象";
rankdir = LR;
node [shape = record];
redisObject [label = " redisObject | type \n REDIS_SET | encoding \n REDIS_ENCODING_HT | <ptr> ptr | ... "];
dict [label = " <head> dict | <cherry> StringObject \n \"cherry\" | <apple> StringObject \n \"apple\" | <banana> StringObject \n \"banana\" ", width = 1.5];
redisObject:ptr -> dict:head;
node [shape = plaintext, label = "NULL"];
dict:apple -> nullX;
dict:banana -> nullY;
dict:cherry -> nullZ;
}](../../_images/graphviz-dedb626ef552a858369fd3504060ce1657e888aa.png)
编码的转换¶
当集合对象可以同时满足以下两个条件时,
对象使用 intset
编码:
集合对象保存的所有元素都是整数值;
集合对象保存的元素数量不超过
512
个;
不能满足这两个条件的集合对象需要使用 hashtable
编码。
对于使用 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"
集合命令的实现¶
因为集合键的值为集合对象, 所以用于集合键的所有命令都是针对集合对象来构建的, 表 8-10 列出了其中一部分集合键命令, 以及这些命令在不同编码的集合对象下的实现方法。
表 8-10 集合命令的实现方法
命令 |
|
|
---|---|---|
SADD |
调用 |
调用 |
SCARD |
调用 |
调用 |
SISMEMBER |
调用 |
调用 |
SMEMBERS |
遍历整个整数集合,
使用 |
遍历整个字典,
使用 |
SRANDMEMBER |
调用 |
调用 |
SPOP |
调用 |
调用 |
SREM |
调用 |
调用 |