最近做到个记录访问人员的需求,具体要求是:记录访问者的ID,一个用户只记入一次。
刚看到这个需求就想到了集合,ES6
标准向 Javascript
里加入了 Set
这个结构。正好做到了这个,就想着用 Redis
的 set
结构实现,而且 Redis
可以设置 ttl
(time to live
)。
Set
Redis
的 Set
是一组无序字符串的集合,查找复杂度为 O(1)
,支持直接向其中插入、删除元素。并且插入前不需要考虑 Set
中是否存在需要插入的元素,这是 Set
的特性:相同的元素只会保留一个。
在 Redis
中使用 Set
最大的优点是 Redis
内置了许多操作方法,比如交集、并集、差集等等,我们可以直接使用 Redis
命令从既有 Set
生成新的 Set
,而不需要书写代码。
Set
的最大容量是 2^32 - 1
,足够应对大部分情形了。
常用命令
SADD
操作:向
Set
插入元素返回:插入成功返回1,元素已存在返回0
SADD myset "id1" // 1 SADD myset "id1" // 0
SISMEMBER
操作:查看元素在
Set
中是否存在返回:是返回1,否返回0
SISMEMBER myset "id1" // 0 SADD myset "id1" // 1 SISMEMBER myset "id1" // 1
SCARD
操作:查看
Set
的Cardinality
,表示Set
里存储的元素数量返回:
Set
中存储的元素数量,如果Set
不存在则返回0SCARD myset // 0 SADD myset "id1" // 1 SCARD myset // 1
SDIFF
操作:计算第一个参数
Set
与剩余参数Set
的差集,key
不存在会被当为空Set
返回:第一个参数
Set
与剩余参数Set
的差集// myset1 {a, b, c, d} // myset2 {a} // myset3 {c} SDIFF myset1 myset2 myset3 // {b, d}
SDIFFSTORE
操作:类似
SDIFF
,但第一个参数表示将最终结果存入的key
,剩余的参数与SDIFF
的参数含义一致返回:最终
Set
的Cardinality
,如果结果的key已存在,则会被覆盖// myset1 {a, b, c, d} // myset2 {a} // myset3 {c} SDIFF final myset1 myset2 myset3 // 2,final中的元素为b、d
SINTER
操作:计算所有参数
Set
交集,key
不存在会被当为空Set
返回:返回参数
Set
的交集// myset1 {a, b, c, d} // myset2 {b, c, d} // myset3 {c, e} SINTER myset1 myset2 myset3 // {c}
SINTERSTORE
操作:类似
SINTER
,但第一个参数表示将最终结果存入的key
,剩余的参数与SINTER
的参数含义一致返回:最终
Set
的Cardinality
,如果结果的key已存在,则会被覆盖
SMEMBERS
操作:查看
Set
中存储的所有元素返回:目标
Set
的所有元素SADD myset "id1" // 1 SADD myset "id2" // 1 SMEMBERS myset // {"id1", "id2"}
SMOVE
操作:将源
Set
中的一个元素移入目标Set
返回:设定操作的元素为A,如果源
Set
中不存在A,则不做任何操作,并返回0;如果源Set
中存在A,则将A移入目标Set
,并返回1;如果源Set
与 目标Set
中均存在A,则将源Set
中的A移除,并返回1;如果源与目标中的任何一个存在但不是Set
结构,抛出错误// myset1 {"id1"} SMOVE myset1 myset2 "id1" // 1 SMOVE myset1 myset2 "id2" // 0 SET myset3 "string value" SMOVE myset2 myset3 "id1" // WRONGTYPE Operation against a key holding the wrong kind of value
SPOP
操作:从
Set
中取出1或多个元素(会改动Set
),第二个参数为要取出的元素个数。返回:bulk string,表示取出的元素,如果key不存在,返回nil。
SPOP
的第二个参数不能为负值,否则直接抛出错误注释:对应到
IORedis
库中,如果未指定第二个参数,返回一个string
或null
;如果指定了第二个参数,返回一个字符串数组(可能为空,可能Cardinality
小于指定的参数大小),这块儿还有许多可以学习的地方,建议参考官方文档文档地址:SPOP-Redis
SRANDMEMBER
操作:从
Set
中取出1或多个元素(不会改动Set
),第二个参数为要取出的元素个数返回:这个操作比较复杂,需要好好解释一下。
- 当只有一个参数的时候,随机返回
Set
中的一个元素;Set
不存在或为空则返回nil
- 当加入了第二个
count
参数的时候,如果参数为正值,返回一个数组;如果参数为负值,这个命令可能会返回一个元素多次,返回数组的大小为count
参数的绝对值。
- 当只有一个参数的时候,随机返回
注释:对应到
IORedis
库中,如果未指定第二个参数,返回一个string
或null
;如果指定了第二个参数,返回一个字符串数组(Cardinality
可能会小于指定的参数大小),这块儿官方文档也有很多解释,包括返回元素的制定规则等等,建议参考文档地址:SRANDMEMBER-Redis
SREM
操作:从
Set
中移除一个或多个元素返回:移除的元素数量,不包括
Set
中不存在的元素SADD myset "id1" // 1 SADD myset "id2" // 2 SREM myset "id1" "id3" // 1
SUNION
操作:计算第一个参数
Set
与剩余参数Set
的并集,key
不存在会被当为空Set
返回:第一个参数
Set
与剩余参数Set
的并集// myset1 {a, b} // myset2 {a, e} // myset3 {c, g} SUNION myset1 myset2 myset3 // {a, b, c, e, g}
SUNIONSTORE
操作:类似
SUNION
,但第一个参数表示将最终结果存入的key
,剩余的参数与SUNION
的参数含义一致返回:最终
Set
的Cardinality
,如果结果的key已存在,则会被覆盖// myset1 {a, b} // myset2 {a, e} // myset3 {c, g} SUNION myset1 myset2 myset3 // 5
SSCAN
- 操作:对
Set
进行扫描,关于Redis
的SCAN
,会专门出一篇讲。