一文了解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为负数时,会有大量的重复数据。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容