Redis 05_Redis无序集合Sets

一、Redis中Sets数据类型简介

1.1 Sets简介

Set(集合) 是 Redis 数据库中的一种数据类型,它是一种 无序的不重复 的数据结构,用于存储一组唯一的元素。Set 在 Redis 中非常实用,因为它提供了高效的成员查找和去重功能,常用于处理一些需要存储唯一值的场景。以下是关于 Redis 中 Set 类型的介绍:

Set 特点和用途:

  • 无序性:Set 中的元素是无序排列的,与元素的插入顺序无关;
  • 唯一性:Set 中的元素是唯一的,不允许出现重复元素;
  • 高效的成员查找:Redis 提供了高效的成员查找操作,可以快速判断一个元素是否存在于集合中;
  • 去重:由于元素的唯一性,Set 常用于去重操作,将一组数据转换为不含重复元素的数据集;
  • 集合运算:Redis 提供了多个集合运算命令,可以对多个集合进行交集、并集和差集等操作;
  • 支持多种数据类型:Set 可以存储字符串、数字、甚至其它 Redis 数据类型的元素;

Set 数据类型适用于需要存储一组唯一值的情况,例如标签、用户的兴趣爱好等。使用合适的 Set 相关命令,可以高效地进行成员的添加、删除、查找以及集合运算。

1.2 Set 类型内部编码及底层结构介绍

Redis 中的 Set 数据类型的内部编码方式有两种,分别是 intsethashtable。这两种编码方式根据集合的大小和元素来选择,以最大程度地节省内存和提高性能。

intset(整数集合)

  • 特点:intset 是 Redis 用于表示只包含整数值的集合的编码方式。它是一个有序的、紧凑的、不可重复的集合,内部使用整数表示元素值。

  • 适用场景:intset 适用于存储小型整数集合,因为它在内存占用和性能方面都非常高效。当集合中的元素都是整数且数量较少时,Redis 会选择使用 intset 编码。

  • 优点:

    • 节省内存:intset 采用紧凑的二进制存储,每个整数只占用所需的字节。
    • 高效的查找和插入:由于元素都是整数且有序,查找和插入操作的时间复杂度是 O(log(N))。

hashtable(哈希表)

  • 特点:hashtable 是 Redis 用于表示包含字符串、浮点数或其它数据类型的集合的编码方式。它是一个无序的、动态大小的集合,内部使用哈希表来存储元素。
  • 适用场景:hashtable 适用于存储包含各种数据类型的集合,以及大型集合,因为它可以动态增长并处理各种数据类型。
  • 优点:
    • 适用性广泛:hashtable 可以存储不同类型的数据,而不仅限于整数。
    • 动态增长:可以随时添加或删除元素,适用于大型集合。

Redis 在使用 Set 类型时会根据集合的内容和大小自动选择 intset 或 hashtable 编码方式,以优化内存和性能。这种智能的编码方式选择是 Redis 内存管理的一部分,使得 Redis 在处理不同类型和大小的集合时能够充分发挥其优势。

二、Sets类型相关命令

2.1 Redis Set相关命令简介

Set(集合)是 Redis 中的一种无序且不重复的数据结构,它包含了一组唯一的成员。以下是关于 Redis Set 相关命令的简介表,包括命令、作用以及时间复杂度:

命令 作用 时间复杂度
SADD 向集合中添加一个或多个成员 O(N) (N 为添加成员的数量)
SMEMBERS 返回集合中的所有成员 O(N) (N 为集合中的元素数量)
SISMEMBER 检查成员是否存在于集合中 O(1)
SCARD 获取集合的基数(成员数量) O(1)
SPOP 随机移除并返回集合中的一个成员 O(1)
SMOVE 将成员从一个集合移动到另一个集合 O(1)
SREM 从集合中移除一个或多个成员 O(N) (N 为移除成员的数量)
SINTER 返回多个集合的交集 O(N*M) (N 和 M 为集合的大小)
SINTERSTORE 将多个集合的交集存储到一个新集合中 O(N*M) (N 和 M 为集合的大小)
SUNION 返回多个集合的并集 O(N+M) (N 和 M 为集合的大小)
SUNIONSTORE 将多个集合的并集存储到一个新集合中 O(N+M) (N 和 M 为集合的大小)
SDIFF 返回第一个集合与其它集合的差集 O(N) (N 为第一个集合的大小)
SDIFFSTORE 将第一个集合与其它集合的差集存储到一个新集合中 O(N) (N 为第一个集合的大小)

2.2 SADD 命令

SADD 命令添加一个或多个指定的 member 元素到集合的 key 中。指定的一个或者多个元素 member 如果已经在集合 key 中存在,则忽略。如果集合 key 不存在,则新建集合 key,并添加 member 元素到集合 key 中。如果 key 的类型不是集合,则返回错误。

Tips: Redis 2.4 以前的版本每次只能添加一个 member 元素,Redis 2.4 版本及之后,接受多个 member 参数。

命令语法:

1
127.0.0.1:6379> SADD key member [member ...]

命令返回值:

  • 如果 key 不存在,创建 集合key,并添加 member 列表数据,返回 添加到集合中的 member元素个数;
  • 如果 key 存在 并且 是集合,忽略已经在集合 key 中存在的指定元素 member,并添加集合 key 中不存在的指定元素 member,返回新添加到集合中的 member元素个数;如果全部元素都已存在 集合key中,返回0;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

2.3 SMEMBERS、SISMEMBER 和 SCARD 命令

1、 SMEMBERS命令 SMEMBERS 命令返回 key 集合所有的元素。该命令的作用与使用一个参数的 SINTER 命令作用相同。不存在的 key 被视为空集合。

命令语法:

1
127.0.0.1:6379> SMEMBERS key

命令返回值:

  • 如果 key 不存在,返回 (empty array);
  • 如果 key 存在 并且 是集合,返回集合中的元素列表;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

2、 SISMEMBER 命令 SISMEMBER 命令判断 member 元素是否是集合 key 的成员。 命令语法:

1
127.0.0.1:6379> SISMEMBER key member

命令返回值:

  • 如果 key 不存在,返回 (empty array);
  • 如果 key 存在 并且 是集合,如果 member 在集合 key 中,返回 1,不在返回 0;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

3、SCARD 命令 SCARD 命令返回集合存储的 key 的基数(集合元素的数量)。 命令语法:

1
127.0.0.1:6379> SCARD key

命令返回值:

  • 如果 key 不存在,返回 0;
  • 如果 key 存在 并且 是集合,返回集合中的元素个数;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

2.4 SPOP、SMOVE 和 SREM

1、 SPOP 命令 SPOP 命令从集合 key 中移除并返回一个或多个随机元素。该操作与 SRANDMEMBER 类似,它从一个集合中返回一个或多个随机元素,但 SRANDMEMBER 不删除元素。 命令语法:

1
127.0.0.1:6379> SPOP key [count]

命令返回值:

  • 如果 key 不存在,返回 (empty array);
  • 如果 key 存在 并且 是集合,从 集合 key 中 删除并返回 count 个元素(列表),如果元素少于 count 数量,则返回 key 中 所有元素,并删除 集合key;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

2、 SMOVE 命令 SMOVE 命令将 member 从 source 集合移动到 destination 集合中。SMOVE 是原子性操作。 命令语法:

1
127.0.0.1:6379> SMOVE source destination member

命令返回值:

  • 如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回0;
  • 如果 source 集合存在 并且 包含指定的 member 元素,
    • 如果 destination 不存在则创建集合 或者 如果存在 且是集合类型,则 member 元素从 source 集合中被移除,并添加到 destination 集合中去,当 destination 集合已经包含 member 元素时,SMOVE 命令只是简单地将 source 集合中的 member 元素删除
  • 当 source 或 destination 不是集合类型时,返回类型不匹配的错误信息;

3、 SREM 命令 SREM 命令从集合 key 中移除一个或多个 member 元素,不存在的 member 元素会被忽略。当 key 不是集合类型,返回一个错误。从 Redis 2.4 版本开始,SREM 可以接受多个元素参数。 命令语法:

1
127.0.0.1:6379> SREM key member [member ...]

命令返回值:

  • 如果 key 不存在,返回 0;
  • 如果 key 存在 并且 是集合,从 集合 key 中 删除指定的 member 并返回删除 member 的个数,如果member 不存在集合中,则忽略不存在的 member;
  • 当指定的 key 不是集合时,返回类型不匹配的错误信息;

2.5 SINTER 和 SINTERSTORE 求交集命令

1、 SINTER 命令 SINTER 命令返回指定所有的集合的成员的交集。不存在的 key 被视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 命令语法:

1
127.0.0.1:6379> SINTER key [key ...]

命令返回值:

  • 如果 key 列表不存在 或者指定的key 列表 至少有一个不存在(为空) 并且 除不为空的以外,其它全部为集合,则返回 (empty array);
  • 如果 key 列表存在 并且 全是集合,返回所有的集合的成员的交集(列表);
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

2、 SINTERSTORE 命令 SINTERSTORE 命令与 SINTER 命令类似,但是它并不是直接返回结果集,而是将结果保存在 destination 集合中。如果 destination 集合存在,则会被覆写。 命令语法:

1
127.0.0.1:6379> SINTERSTORE destination key [key ...]

命令返回值:

  • 如果 key 列表不存在 或者指定的key 列表 至少有一个不存在(为空) 并且 除不为空的以外,其它全部为集合,则返回 0;
  • 如果 key 列表存在 并且 全是集合,所有的集合的成员的交集(列表)存入 destination,如果 destination 是其它类型的 key,将被交集覆盖,并返回交集的元素数量;
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

2.6 SUNION 和 SUNIONSTORE 求并集命令

1、 SUNION 命令 SUNION 命令返回指定所有的集合的成员的交集。不存在的 key 被视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 命令语法:

1
127.0.0.1:6379> SUNION key [key ...]

命令返回值:

  • 如果 key 列表全不存在,则返回 (empty array);
  • 如果 key 列表存在 并且 全是集合,返回所有的集合的成员的并集(列表);
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

2、 SINTERSTORE 命令 SUNIONSTORE 命令与 SUNION 命令类似,但是它并不是直接返回结果集,而是将结果保存在 destination 集合中。如果 destination 集合存在,则会被覆写。 命令语法:

1
127.0.0.1:6379> SUNIONSTORE destination key [key ...]

命令返回值:

  • 如果 key 列表全不存在,则返回 (empty array);
  • 如果 key 列表存在 并且 全是集合,所有的集合的成员的并集(列表)存入 destination,如果 destination 是其它类型的 key,将被并集覆盖,并返回并集的元素数量;
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

2.7 SDIFF 和 SDIFFSTORE 求差集命令

1、 SDIFF 命令 SDIFF 命令返回一个集合与给定集合的差集的元素。不存在的 key 被认为是空集。 命令语法:

1
127.0.0.1:6379> SDIFF key [key ...]

命令返回值:

  • 如果第一个 key 不存在,后续 key 不存在或全部为集合,则返回 (empty array);
  • 如果第一个 key 存在并且所有key 都是集合,或 不存在,则返回第一个集合与后面给定集合的差集的元素;
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

2、 SINTERSTORE 命令 SDIFFSTORE 命令类似于 SDIFF,不同之处在于该命令不返回结果集,而是将结果存放在 destination 集合中。如果 destination 已经存在,则将其覆盖重写。 命令语法:

1
127.0.0.1:6379> SUNIONSTORE destination key [key ...]

命令返回值:

  • 如果第一个 key 不存在,后续 key 不存在或全部为集合,则返回 (empty array);
  • 如果第一个 key 存在并且所有key 都是集合,或 不存在,把第一个集合与后面给定集合的差集的元素存入 destination, 并返回差集的元素数量;;
  • 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;

三、应用场景

3.1 需要存放的数据不能重复的场景

举例:网站 UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。 相关命令:SCARD(获取集合数量) 。

3.2 需要获取多个数据源交集、并集和差集的场景

举例:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等场景。 相关命令:SINTER(交集)、SINTERSTORE (交集)、SUNION (并集)、SUNIONSTORE(并集)、SDIFF(差集)、SDIFFSTORE (差集)。

3.3 需要随机获取数据源中的元素的场景

举例:抽奖系统、随机点名等场景。 相关命令:SPOP(随机获取集合中的元素并移除,适合不允许重复中奖的场景)、SRANDMEMBER(随机获取集合中的元素,适合允许重复中奖的场景)。****