一文了解Redis集合类型

集合类型

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。指令为原子操作。

当指定的membersource集合中不存在时,不进行任何操作,返回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为负数时,会有大量的重复数据。

你可能感兴趣的:(一文了解Redis集合类型)