第七章:进入Redis的SET核心

一.SET概念

集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中1)元素之间是无序的2)元素不可重复。一个集合中最多可以存储无数个元素。Redis除了支持集合内的增删查改操作,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多问题。

  • 谈到一个术语,这个术语很可能有多种含义。
  • Set:
    1. 集合。
    2. 设置(和 get 相对应)。
  • 集合就是把一些有关联的数据放到一起。
    1. 集合中的元素是无序的!
    2. 集合中的元素是不能重复的(唯一的)。
  • 此处说的无序和前面 list 这里的有序是对应的。
    • 有序:顺序很重要。变换一下顺序,就是不同的 list 了。
    • 无序:顺序不重要。变化一下顺序,集合还是那个集合。
    • 示例:
      • list:[1, 2, 3][2, 1, 3] 是两个不同的 list。
      • set:[1, 2, 3][2, 1, 3] 是同一个集合。
  • 和 list 类似,集合中的每个元素也都是 string 类型。(可以使用 json 这样的格式让 string 也能存储结构化数据)。

二.SET核心命令

SADD 命令:将⼀个或者多个元素添加到 set 中。注意,重复的元素⽆法添加到 set 中。

复制代码
SADD key member [member ...]

时间复杂度:O(1)
返回值:本次添加成功的元素个数

2.1SADD


2.2SMEMBERS

SMEMBERS命令:获取⼀个 set 中的所有元素,注意,元素间的顺序是无序的。

复制代码
SMEMBERS key

时间复杂度:O(N)
返回值:所有元素的列表


2.3SISMEMBER

SISMEMBER命令:判断⼀个元素在不在 set 中。

复制代码
SISMEMBER key member

时间复杂度:O(1)
返回值:1 表⽰元素在 set 中。0 表⽰元素不在 set 中或者 key 不存在


2.4SPOP

SPOP 命令:从 set 中删除并返回⼀个或者多个元素。

  • spop 删除元素的时候其实是随机删除。

  • 不写 count 的时候,随机删除一个;写 count 的时候,就写几个就删几个。

  • 该操作类似于 SRANDMEMBERSRANDMEMBER 从集合中返回一个或多个随机元素但不删除它。

  • 其实是在源码中,针对 spop 实现的时候采取了 "生成随机数" 的方式。

    SPOP key [count]

时间复杂度:O(N), n 是 count
返回值:取出的元素。

存储元素是无序的,删除随机删


2.5SMOVE

SMOVE 命令:将⼀个元素从源 set 取出并放⼊目标 set 中。

  • 把 member 从 source 上删除,再插入到 destination 中。

再次操作时,smove 不会视为出错,也会按照删除 - 插入进行执行。

如果要移动的元素在 source 中不存在,返回 (integer) 0 表示移动失败了。

复制代码
SMOVE source destination member

时间复杂度:O(1)
返回值:1 表示移动成功,0 表示失败


2.6 SREM

SREM 命令:将指定的元素从 set 中删除。

可以一次删除一个 member,也可以一次删除多个 member。

复制代码
SREM key member [member ...]

时间复杂度:O(N), N 是要删除的元素个数.
返回值:本次操作删除的元素个数


2.7SCARD

SCARD 命令:获取⼀个 set 的基数(cardinality),即 set 中的元素个数。

复制代码
SCARD key

时间复杂度:O(1)
返回值:set 内的元素个数。


2.8 SRANDMEMBER

SRANDMEMBER命令:随机返回集合中的某个元素


相关概念:

1.交集(inter):最终结果同时出现在两个集合中。

示例:A 为 {1, 2, 3, 4},B 为 {3, 4, 5, 6},A 和 B 的交集为 {3, 4}。

2.并集(union):把多个集合中的数据都集中放在一起,如果元素有重复,也最终只保留一份。

示例:A 为 {1, 2, 3, 4},B 为 {3, 4, 5, 6},A 和 B 的并集为 {1, 2, 3, 4, 5, 6}。

3.差集(diff):A 和 B 做差集,就是找出哪些元素在 A 中存在,同时在 B 中不存在。

示例:A 为 {1, 2, 3, 4},B 为 {3, 4, 5, 6},A 和 B 做差集为 {1, 2},B 和 A 的差集为 {5, 6}。

2.9SINTER ,SINTERSTSTORE

SINTER命令:获取给定 set 的交集中的元素。

复制代码
 SINTER key [key ...]

时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最大的集合元素个数.
返回值:交集的元素。


SINTERSTORE命令:获取给定 set 的交集中的元素并保存到⽬标 set 中。

复制代码
SINTERSTORE destination key [key ...]

时间复杂度:O(N * M), N 是最小的集合元素个数. M 是最大的集合元素个数.
返回值:交集的元素个数


2.10SUNION, SUNIONSTORE

SUNION命令:获取给定 set 的并集中的元素。

复制代码
 SUNION key [key ...]

时间复杂度:O(N), N 给定的所有集合的总的元素个数.
返回值:并集的元素

SUNIONSTORE命令:获取给定 set 的并集中的元素并保存到目标 set 中。

复制代码
SUNIONSTORE destination key [key ...]

命令有效版本:1.0.0 之后
时间复杂度:O(N), N 给定的所有集合的总的元素个数.
返回值:并集的元素个数。


2.11SDIFF,SDIFFSTORE

SDIFF命令:获取给定 set 的差集中的元素。

复制代码
SDIFF key [key ...]

时间复杂度:O(N), N 给定的所有集合的总的元素个数.
返回值:差集的元素。


SDIFFSTORE 命令:获取给定 set 的差集中的元素并保存到⽬标 set 中。

复制代码
SDIFFSTORE destination key [key ...]

时间复杂度:O(N), N 给定的所有集合的总的元素个数.
返回值:差集的元素个数


三.SET内部编码

  • intset(整数集合):当集合中的元素都是整数并且元素的个数小于 set-max-intset-entries 配置(默认 512 个)时,Redis 会选用 intset 来作为集合的内部实现,从而减少内存的使用。
  • hashtable(哈希表):当集合类型无法满足 intset 的条件时,Redis 会使用 hashtable 作为集合的内部实现。

1.当元素个数较少并且都为整数时,内部编码为 intset:

复制代码
127.0.0.1:6379> sadd setkey 1 2 3 4
(integer) 4
127.0.0.1:6379> object encoding setkey
"intset"

2.当元素个数超过 512 个,内部编码为 hashtable

复制代码
127.0.0.1:6379> sadd setkey 1 2 3 4
(integer) 513
127.0.0.1:6379> object encoding setkey
"hashtable"

3.当存在元素不是整数时,内部编码为 hashtable

复制代码
127.0.0.1:6379> sadd setkey a
(integer) 1
127.0.0.1:6379> object encoding setkey
"hashtable"

四.SET的应用场景

集合类型比较典型的使用场景是标签(tag)。例如 A 用户对娱乐、体育板块比较感兴趣,B 用户对历史、新闻比较感兴趣,这些兴趣点可以被抽象为标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于增强用户体验和用户黏度都非常有帮助。 例如一个电子商务网站会对不同标签的用户做不同的产品推荐。

  1. 使用 Set 来保存用户的 "标签"(用户画像)
    • 分析出个人的一些特征,分析清楚特征之后,再投其所好,实现 "千人千面",例如可以分析出性别、年龄、居住地、爱好等特征。
    • 可以根据用户的一些历史行为得出相关特征。
    • 比如对于两个程序、两个账号,判断是否为同一个人,现在的程序登录主要是通过手机号和微信等入口来判断。
    • 通过上述过程搜集到的用户特征,会转换成 "标签",标签是简短的字符串,此时就可以把标签保存到 redis 的 set 中了。
  2. 使用 Set 来计算用户之间的共同好友
    • 基于 "集合求交集" 操作。
    • 例如在 QQ 中,我加了很多好友,你也加了很多好友,基于此还可以做一些好友推荐。
    • 如 A 和 B 是好友,A 和 C 是好友,B 和 C、D 都是好友,系统就会把 D 推荐给 A。
  3. 使用 Set 统计 UV(去重)
    • 一个互联网产品,衡量用户量、用户规模主要有两方面指标:
      • PV(page view):用户每次访问该服务器,每次访问都会产生一个 pv。
      • UV(user view):每个用户访问服务器,都会产生一个 uv,但同一个用户多次访问,不会使 uv 增加,uv 需要按照用户进行去重,上述的去重过程,可以使用 set 来实现。
  4. Set 方便计算交集
    • 很容易找到两个用户之间的公共标签。
    • 基于这样的标签,衍生出一些 "用户关系"。