集合类型
Redis集合类型中,元素是不重复的,即每个元素在集合中都是唯一的;不同于列表类型,集合的元素没有顺序,与插入的先后没有关系;最多存储2^32 - 1
个元素。常见的操作为添加、删除元素;判断元素是否存在,这些操作的时间负责度为O(1)。
命令
添加元素
SADD key member [member ...]
SADD指令用于向集合中增加一个或多个元素,键不存在时自动创建集合。返回值为加入到集合的元素数量;如果一条指令中某个元素在集合中已存在,添加时将忽略该元素,返回的数量中也不包含该元素。
# 集合a不存在,第一次执行将创建集合,并添加元素
SADD a 1 2 3
# (integer) 3
SADD a 2 4 2 # 因为2已经在集合中存在,因此两个2都会被忽略,只有4添加成功
# (integer) 1
SMEMBERS a
# "1" "2" "3" "4"
删除元素
SREM key member [member ...]
SREM指令用于从集合中删除一个或多个元素,并返回删除的元素个数。当元素不存在时,忽略。
SMEMBERS a
# "1" "2" "3" "4"
SREM a 2 3 5 3 # 5不存在该元素,忽略,3第一个删除成功,第二个3不存在忽略,因此只删除成功2个元素
# (integer) 2
获取集合所有元素
SMEMBERS key
SMEMBERS指令返回集合中的所有元素。
SMEMBERS a
# "1" "4"
判断元素是否在集合中
SISMEMBER key member
SISMEMBER指令用于在key
集合中判断元素member
是否存在,时间复杂度为O(1),判断元素是否存在于集合大小无关。当member
在集合中存在时,返回1
;当member
不存在或key
不存在时,返回0
。
SMEMBERS a
# "1" "4"
SISMEMBER a 1
# (integer) 1
SISMEMBER b 1 # 键b的集合不存在
# (integer) 0
SISMEMBER a 5 # 5元素不存在
# (integer) 0
集合差集
SDIFF key [key ...]
SDIFF指令用于计算多个集合之间的差集。集合A与B的差集描述为A-B
,所有属于A同时不属于B的元素
称之为A与B的差集;指令返回值为差集集合。见下图红色部分即为A与B的差集。
A -B
,当A不存在或为空集合时,运算结果为空(empty list or set)
A - B
,当B为空或不存在时,运算结果为A
如果一个集合A={1,2,3}
,集合B={3,4,5}
,如下图所示,红色为集合A,蓝色为集合B,则A-B={1,2,3}-{3,4,5}={1,2}
,排除了集合B中的4,5元素,同时排除了A与B的交集元素3。
对于SDIFF指令,可以进行多个key的运算,如SDIFF a b c
,其描述的是先计算d=a-b
,此时得出一个新的集合d
,之后再计算d-c
,即为该指令的结果;当SDIFF指令有多个键时,顺序从左至右计算,每两个集合计算差集,结果再与之后的键进行差集计算,直至完成所有键差集运算。参加图示。
Redis的差集指令使用方式如下:
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "3" "4" "5"
SDIFF a b # a - b = {1,2,3}-{3,4,5}={1,2}
# "1" "2"
SMEMBERS C
# "1" "6" "7"
SDIFF a b c # a - b = {1, 2} c={1,6 7},则 a-b-c={2}
# "2"
集合交集
SINTER key [key ...]
SINTER指令实现多个集合之间的交集运算。A∩B
描述了A与B的交集,所有属于A且属于B的元素集合
称为A与B的交集;指令返回运算后的交集集合。
A∩B
,当A或B不存在或为空时,运算结果为空(empty list or set)
上图中斜线部分即为A∩B
。假如集合A={1,2,3}
,集合B={3,4,5}
,则A∩B={1,2,3}∩{3,4,5}={3}
,如下图所示,红色为集合A,蓝色为集合B,当A∩B其只有中间的红色元素3
,是两者的公共部分。
同SDIFF指令一样,SINTER指令也支持多个集合的运算,如SINTER a b c
,其描述的是先计算d=a∩b
,此时得出一个新的集合d
,之后再计算d∩c
,即为该指令的结果;当SINTER指令有多个键时,顺序从左至右计算,每两个集合计算交集,结果再与之后的键进行交集计算,直至完成所有键交集运算。参加图示。
上图中,计算A∩B={3},其第一步计算的结果集合是第三个集合的子集,此时在进行计算两者交集时,结果为A∩B。
使用Redis进行交集计算
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "2" "3" "4"
SINTER a b # a ∩ b = {1,2,3}∩{2,3,4}={2,3}
# "2" "3"
SMEMBERS C
# "2" "4" "5"
SINTER a b c # a ∩ b = {1,2,3}∩{2,3,4}={2,3} , c={2,4,5},则 a∩b∩c={2}
# "2"
集合并集
SUNION key [key ...]
SUNION指令用于计算多个集合的并集;A∪B
描述了两个集合A与B的并集。A∪B是所有属于A或属于B的元素集合
称为A与B的并集。指令返回并集集合。
A∪B
,如果B为空或不存在的集合,则运算结果为A
上图所有蓝色区域为A∪B。假如集合A={1,2,3}
,集合B={3,4,5}
,则A∪B={1,2,3}∪{3,4,5}={1,2,3,4,5}
,如下图所示,红色为集合A,蓝色为集合B,当进行A∪B运算时,返回的是全部蓝色部分的集合。
同SDIFF指令一样,SUNION指令也支持多个集合的运算,如SUNION a b c
,其描述的是先计算d=a∪b
,此时得出一个新的集合d
,之后再计算d∪c
,即为该指令的结果;当SUNION指令有多个键时,顺序从左至右计算,每两个集合计算并集,结果再与之后的键进行并集计算,直至完成所有键并集运算。参加图示。
Redis使用并集指令操作
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "2" "3" "4"
SUNION a b # a ∪ b = {1,2,3}∪{2,3,4}={1,2,3,4}
# "2" "3"
SMEMBERS C
# "2" "4" "5"
SINTER a b c # a ∪ b = {1,2,3}∪{2,3,4}={1,2,3,4} , c={2,4,5},则 a∪b∪c={1,2,3,4,5}
# "1" "2" "3" "4" "5"
获取元素的个数
SCARD key
SCARD指令用于返回key集合的元素个数。
SMEMBERS a
# "1" "2" "3"
SCARD a
# (integer) 3
集合差集并存储到目标集合
SDIFFSTORE destination key [key ...]
SDIFFSTORE指令,包含了SDIFF和STORE两部分,第一部分同SDIFF指令一样,执行多个key集合的差集运算,计算方式同SDIFF一致;在计算完成差集后,会将差集结果存储到目标集合中destination
。返回结果为存储到目标集合中的差集集合个数。
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "2" "4" "5"
SDIFFSTORE d a b
# (integer) 2
SMEMBERS d
# "1" "3"
集合交集并存储到目标集合
SINTERSTORE destination key [key ...]
SINTERSTORE指令,包含了SINTER和STORE两部分,第一部分同SINTER指令一样,执行多个key集合的交集运算,计算方式同SINTER一致;在计算完成交集后,会将差集结果存储到目标集合中destination
。返回结果为存储到目标集合中的交集集合个数。
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "2" "3" "4"
SINTERSTORE d a b
# (integer) 2
SMEMBERS d
# "2" "3"
集合并集并存储到目标集合
SUNIONSTORE destination key [key ...]
SUNIONSTORE指令,包含了SUNION和STORE两部分,第一部分同SUNION指令一样,执行多个key集合的并集运算,计算方式同SUNION一致;在计算完成并集后,会将差集结果存储到目标集合中destination
。返回结果为存储到目标集合中的并集集合个数。
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "2" "3" "4"
SUNIONSTORE d a b
# (integer) 4
SMEMBERS d
# "1" "2" "3" "4"
随机弹出一个或多个元素
SPOP key [count]
集合元素是无序的,因此SPOP指令会随机选择一个或多个元素弹出,并返回弹出的元素信息。
count
当不指定该参数时,默认弹出一个,如SPOP d
count=0
则不弹出任何元素,返回空集合(empty list or set)
count>0
按count指定的个数,随机弹出元素;当个数大于集合长度时,全部弹出
count<0
异常
SMEMBERS d
# "1" "2" "3" "4"
SPOP d
# "2"
SMEMBERS d
# "1" "3" "4"
SPOP d 2
# "1" "3"
SPOP d 0
# (empty list or set)
SMEMBERS d
# "4"
SPOP d 2
# "4"
移动元素到新集合
SMVOE source destination member
SMOVE指令,将元素member
从源source
集合移除,并将该元素添加到目标集合中destination
。指令为原子操作。
当指定的
member
在source
集合中不存在时,不进行任何操作,返回0
当指定的
member
存在于source
集合时,执行从source
集合中删除member
元素,并返回1
;当destination
中不包含member
时,执行添加操作。
SMEMBERS a
# "1" "2" "3"
SMEMBERS b
# "1"
SMOVE a b 4 # 元素4在a中不存在,不执行任何操作
# (integer) 0
SMOVE a b 2
# (integer) 1
SMEMBERS a
# "1" "3"
SMEMBERS b
# "1" "2"
SMOVE a b 1 # 1存在于a,执行删除,在b中已存在1,因此该操作相当于只移除了a中的元素1
# (integer) 1
SMEMBERS a
# "3"
SMEMBERS b
# "1" "2"
随机返回集合中的元素
SRANDMEMBER key [count]
SRANDMEMBER指令用来从key
集合中随机获取一个或多个(count
决定)元素。该指令只随机返回一定数量的元素,并不会对源集合产生任何修改。
当不设置
count
参数时,默认只随机返回一个元素
count>0
时,指令会随机从源集合中获取count
个不重复元素;当count
大于或等于源集合的元素个数时,该指令将返回全部元素。
count<0
时,指令会随机从集合获取abs(count)
个元素,元素可能重复(即使abs(count)小于集合元素个数时,也可能会重复
),严格按照abs(count)返回。
count=0
时,指令返回空。
SMEMBERS a # 集合a包含从1到5共五个数字元素
# "1" "2" "3" "4" "5"
SRANDMEMBER a # 不包含count参数,默认count=1
# "1"
SRANDMEMBER a
# "3"
SRANDMEMBER a 0
# (empty list or set)
SRANDMEMBER a 2
# "4"
# "2"
SRANDMEMBER a 5 # 返回全部列表元素
# "1"
# "2"
# "3"
# "4"
# "5"
SRANDMEMBER a 7 # 超过元素集合数量,同样返回全部的元素,返回数不足目标数
# "1"
# "2"
# "3"
# "4"
# "5"
SRANDMEMBER a -2 # 负数时,返回abs(count)个元素,不保证不重复
# "4"
# "4"
SRANDMEMBER a -7 # abs(count)超过元素数量,但返回数量等于abs(count),但会有重复,返回不一定包含所有元素
# "2"
# "3"
# "2"
# "1"
# "1"
# "1"
# "4"
Redis的集合数据结构,为了实现查找事件复杂度为O(1),采用了散列表的形式,类似于JDK1.7的HashMap结构,采用数组+链表的形式进行存储。每一个元素都会按照一定的算法,计算出一个hash值,决定了存储的数组位置,相同的hash值内部采用类似的链表结构存储。
而随机返回集合元素的指令,Redis会先随机查找一个位置(hash位置),然后再从链表中随机选择一个元素。当一个位置的链表上只有一个元素时,其被选中的机会将增大,因此当使用count为负数时,会有大量的重复数据。