集合(Set)类型的值是字符串的无序集合,并且每个值都是唯一的。本文将介绍 Redis Set 的常用命令包含示例、Set的内部编码以及使用场景。
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是,集合中
1)元素之间是无序的
2)元素不允许重复,如图 所示。一个集合中最多可以存储 2^32- 1个元素。
Redis 除了支持集合内的增删查改操作,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多问题。
1. 常用命令
命令 | 描述 | 时间复杂度 |
SADD key element [element ...] | 将一个或多个元素添加到集合中,已经存在的元素会被忽略 | O(k),k是元素个数 |
SREM key element [element ...] | 移除集合中的一个或多个元素,不存在的元素会被忽略 | O(k),k是元素个数 |
SCARD key | 获取集合中元素的数量 | O(1) |
SISMEMBER key element | 判断元素是否是集合的成员 | O(1) |
SRANDMEMBER key [count] | 随机返回集合中的一个或多个元素 | O(n),n是count |
SPOP key [count] | 移除并返回集合中的一个或多个随机元素 | O(n),n是count |
SMEMBERS key | 返回集合中的所有成员 | O(k),k是元素个数 |
SINTER key [key ...] | 返回所有给定集合的交集 | O(m*k),k是几个集合中元素最小的个数,m是键个数 |
SUNION key [key ...] | 返回所有给定集合的并集 | O(k),k是多个集合的元素个数总和 |
SDIFF key [key ...] | 返回给定集合之间的差集 | O(k),k是多个集合的元素个数总和 |
2. 内部编码
Redis 的 Set 是一个无序集合,它的内部编码实现取决于 Set 中元素的数量和元素的大小。Redis 使用两种不同的编码方式来存储 Set:intset 和 hashtable。下面我们将详细介绍这两种编码方式以及它们的适用场景。
2.1 intset 编码
当 Set 中的元素全部是整数,并且数量较少时,Redis 使用 intset(整数集合)编码方式来存储 Set。intset 是一种紧凑的存储结构,适用于存储小规模的整数集合。具体来说:
intset(整数集合):当集合中的元素都是整数并且元素的个数小于 set-max-intset-entries 配置
(默认 512 个)时,Redis 会选用 intset 来作为集合的内部实现,从而减少内存的使用。
intset 的特性
- 存储紧凑:intset 使用紧凑的内存布局,存储效率高,适用于存储少量整数。
- 自动扩展:当向 intset 添加新的整数时,Redis 会自动扩展存储空间以容纳新的元素。
- 元素唯一:intset 保证集合中的每个整数都是唯一的,自动去重。
127.0.0.1:6379> SADD myset 1 2 3
(integer) 3
127.0.0.1:6379> OBJECT ENCODING myset
"intset"
2.2 hashtable 编码
当 Set 中的元素不是整数,或者元素数量较多时,Redis 使用 hashtable(哈希表)编码方式来存储 Set。hashtable 是一种基于哈希表的数据结构,适用于存储大规模的集合。具体来说:
hashtable(哈希表):当集合类型无法满足intset 的条件时(不是整数,或者元素数量较多时),Redis 会使用 hashtable 作为集合的内部实现。
hashtable 的特性
- 高效查找:hashtable 使用哈希表结构,支持高效的元素查找操作。
- 动态扩展:hashtable 可以根据元素数量的增加自动扩展存储空间,以保持高效的查找性能。
- 元素唯一:hashtable 保证集合中的每个元素都是唯一的,自动去重。
127.0.0.1:6379> SADD myset "apple" "banana" "cherry"
(integer) 3
127.0.0.1:6379> OBJECT ENCODING myset
"hashtable"
3. 使用场景
集合类型比较典型的使用场景是标签(tag)。例如A用户对娱乐、体育板块比较感兴趣,B用户对历史、新闻比较感兴趣,这些兴趣点可以被抽象为标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于增强用户体验和用户黏度都非常有帮助。例如一个电子商务网站会对不同标签的用户做不同的产品推荐。