一、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 数据类型的内部编码方式有两种,分别是 intset
和 hashtable
。这两种编码方式根据集合的大小和元素来选择,以最大程度地节省内存和提高性能。
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 参数。
命令语法:
|
|
命令返回值:
- 如果 key 不存在,创建 集合key,并添加 member 列表数据,返回 添加到集合中的 member元素个数;
- 如果 key 存在 并且 是集合,忽略已经在集合 key 中存在的指定元素 member,并添加集合 key 中不存在的指定元素 member,返回新添加到集合中的 member元素个数;如果全部元素都已存在 集合key中,返回0;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
2.3 SMEMBERS、SISMEMBER 和 SCARD 命令
1、 SMEMBERS命令 SMEMBERS 命令返回 key 集合所有的元素。该命令的作用与使用一个参数的 SINTER 命令作用相同。不存在的 key 被视为空集合。
命令语法:
|
|
命令返回值:
- 如果 key 不存在,返回 (empty array);
- 如果 key 存在 并且 是集合,返回集合中的元素列表;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
2、 SISMEMBER 命令 SISMEMBER 命令判断 member 元素是否是集合 key 的成员。 命令语法:
|
|
命令返回值:
- 如果 key 不存在,返回 (empty array);
- 如果 key 存在 并且 是集合,如果 member 在集合 key 中,返回 1,不在返回 0;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
3、SCARD 命令 SCARD 命令返回集合存储的 key 的基数(集合元素的数量)。 命令语法:
|
|
命令返回值:
- 如果 key 不存在,返回 0;
- 如果 key 存在 并且 是集合,返回集合中的元素个数;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
2.4 SPOP、SMOVE 和 SREM
1、 SPOP 命令 SPOP 命令从集合 key 中移除并返回一个或多个随机元素。该操作与 SRANDMEMBER 类似,它从一个集合中返回一个或多个随机元素,但 SRANDMEMBER 不删除元素。 命令语法:
|
|
命令返回值:
- 如果 key 不存在,返回 (empty array);
- 如果 key 存在 并且 是集合,从 集合 key 中 删除并返回 count 个元素(列表),如果元素少于 count 数量,则返回 key 中 所有元素,并删除 集合key;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
2、 SMOVE 命令 SMOVE 命令将 member 从 source 集合移动到 destination 集合中。SMOVE 是原子性操作。 命令语法:
|
|
命令返回值:
- 如果 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 可以接受多个元素参数。 命令语法:
|
|
命令返回值:
- 如果 key 不存在,返回 0;
- 如果 key 存在 并且 是集合,从 集合 key 中 删除指定的 member 并返回删除 member 的个数,如果member 不存在集合中,则忽略不存在的 member;
- 当指定的 key 不是集合时,返回类型不匹配的错误信息;
2.5 SINTER 和 SINTERSTORE 求交集命令
1、 SINTER 命令 SINTER 命令返回指定所有的集合的成员的交集。不存在的 key 被视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 命令语法:
|
|
命令返回值:
- 如果 key 列表不存在 或者指定的key 列表 至少有一个不存在(为空) 并且 除不为空的以外,其它全部为集合,则返回 (empty array);
- 如果 key 列表存在 并且 全是集合,返回所有的集合的成员的交集(列表);
- 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;
2、 SINTERSTORE 命令 SINTERSTORE 命令与 SINTER 命令类似,但是它并不是直接返回结果集,而是将结果保存在 destination 集合中。如果 destination 集合存在,则会被覆写。 命令语法:
|
|
命令返回值:
- 如果 key 列表不存在 或者指定的key 列表 至少有一个不存在(为空) 并且 除不为空的以外,其它全部为集合,则返回 0;
- 如果 key 列表存在 并且 全是集合,所有的集合的成员的交集(列表)存入 destination,如果 destination 是其它类型的 key,将被交集覆盖,并返回交集的元素数量;
- 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;
2.6 SUNION 和 SUNIONSTORE 求并集命令
1、 SUNION 命令 SUNION 命令返回指定所有的集合的成员的交集。不存在的 key 被视为空集。当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。 命令语法:
|
|
命令返回值:
- 如果 key 列表全不存在,则返回 (empty array);
- 如果 key 列表存在 并且 全是集合,返回所有的集合的成员的并集(列表);
- 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;
2、 SINTERSTORE 命令 SUNIONSTORE 命令与 SUNION 命令类似,但是它并不是直接返回结果集,而是将结果保存在 destination 集合中。如果 destination 集合存在,则会被覆写。 命令语法:
|
|
命令返回值:
- 如果 key 列表全不存在,则返回 (empty array);
- 如果 key 列表存在 并且 全是集合,所有的集合的成员的并集(列表)存入 destination,如果 destination 是其它类型的 key,将被并集覆盖,并返回并集的元素数量;
- 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;
2.7 SDIFF 和 SDIFFSTORE 求差集命令
1、 SDIFF 命令 SDIFF 命令返回一个集合与给定集合的差集的元素。不存在的 key 被认为是空集。 命令语法:
|
|
命令返回值:
- 如果第一个 key 不存在,后续 key 不存在或全部为集合,则返回 (empty array);
- 如果第一个 key 存在并且所有key 都是集合,或 不存在,则返回第一个集合与后面给定集合的差集的元素;
- 当指定的 key 列表有至少一个不是集合时,返回类型不匹配的错误信息;
2、 SINTERSTORE 命令 SDIFFSTORE 命令类似于 SDIFF,不同之处在于该命令不返回结果集,而是将结果存放在 destination 集合中。如果 destination 已经存在,则将其覆盖重写。 命令语法:
|
|
命令返回值:
- 如果第一个 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(随机获取集合中的元素,适合允许重复中奖的场景)。****