【Redis初阶】Set 集合
Hi~!这里是奋斗的明志,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
🌱🌱个人主页:奋斗的明志
🌱🌱所属专栏:Redis
📚本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。
Set集合
- 前言
- 一、普通命令
- 1. SADD
- 2. SMEMBERS
- 3.SISMEMBER
- 4.SPOP
- 5.SMOVE
- 6.SREM
- 二、集合间操作
- 1.SREM
- 2.SINTERSTORE
- 3.SUNION
- 4.SUNIONSTORE
- 5.SDIFF
- 6.SDIFFSTORE
- 三、命令小结
- 四、编码方式
- 五、应用场景
- 1.给用户添加标签(使用set来保存用户的“标签”)
- 2.给标签添加用户
- 3.删除用户下的标签
- 4.删除标签下的用户
- 5.计算用户的共同兴趣标签
前言
集合类型也是保存多个字符串类型的元素的,但和列表类型不同的是
1)set集合中元素之间是无序的
(这里的无序是和前面 list 的有序是对应的
有序:顺序很重要,变换一下顺序,就是不同的list
无序:顺序不重要,变换一下顺序,集合还是呢个集合)
2)元素不允许重复(唯一的),如图所示。一个集合中最多可以存储 2 ^32 - 1 个元素。
Redis 除了支持集合内的增删查改操作,同时还⽀持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多问题。
- 如图 集合类型 :
和list类似,集合中的每个元素,也都是 String 类型。(也可以使用 JSON 这样的格式让 String 也能存储结构化数据)
一、普通命令
- 打开 xSell8 启动云服务器
- 输入以下命令进行 Redis 客户端
root@iZ2ze1wowvpkkp7wnart6oZ:~# redis-cli
- FLUSHALL命令(清空数据库)
1. SADD
- 将一个或者多个元素添加到 set 中。注意,重复的元素无法添加到 set 中。
- 语法:
SADD key member [member ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(1)
- 返回值:本次添加成功的元素个数。
- 示例:
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> type key
set
127.0.0.1:6379> sadd key2 1 1 1 2 3 4
(integer) 4
2. SMEMBERS
- 获取⼀个 set 中的所有元素,注意,元素间的顺序是无序的。
- 语法:
SMEMBERS key
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N)
- 返回值:所有元素的列表。
- 示例:
127.0.0.1:6379> SMEMBERS key
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SMEMBERS key2
1) "1"
2) "2"
3) "3"
4) "4"
3.SISMEMBER
- 判断⼀个元素在不在 set 中。
- 语法:
SISMEMBER key member
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(1)
- 返回值:1 表示元素在 set 中。0 表示元素不在 set 中或者 key 不存在。
- 示例:
127.0.0.1:6379> SISMEMBER key 1
(integer) 1
127.0.0.1:6379> SISMEMBER key 100
(integer) 0
4.SPOP
- 从 set 中删除并返回⼀个或者多个元素。注意,由于 set 内的元素是无序的,所以取出哪个元素实际是未定义行为,是随机的。
- 语法:
SPOP key [count]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), n 是 count
- 返回值:取出的元素。
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> SADD key 1 2 3 4
(integer) 4
127.0.0.1:6379> SPOP key
"2"
127.0.0.1:6379> SPOP key
"4"
127.0.0.1:6379> SPOP key
"1"
127.0.0.1:6379> SPOP key
"3"
127.0.0.1:6379> SADD key2 1 2 3 4
(integer) 4
127.0.0.1:6379> SPOP key2
"2"
127.0.0.1:6379> SPOP key2
"1"
127.0.0.1:6379> SPOP key2
"3"
127.0.0.1:6379> SPOP key2
"4"
这个命令和 SRANDMEMBER 这个命令类似,SRANDMEMBER就是获取一个或者多个元素(不会删除)
在redis源码中,针对 spop 实现的时候,就采取了“生成随机数”的方式。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> SMEMBERS key
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SRANDMEMBER key
"3"
127.0.0.1:6379> SRANDMEMBER key
"3"
127.0.0.1:6379> SRANDMEMBER key
"2"
127.0.0.1:6379> SRANDMEMBER key
"2"
127.0.0.1:6379> SRANDMEMBER key
"3"
127.0.0.1:6379> SRANDMEMBER key 10
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SRANDMEMBER key 2
1) "4"
2) "1"
127.0.0.1:6379> SRANDMEMBER key 2
1) "3"
2) "2"
应用:这里就可以实现随机抽奖
5.SMOVE
- 将一个元素从源 set 取出并放⼊⽬标 set 中。
- 语法:
SMOVE source destination member
// 把 member 从 source 删除,再插入到 destination 中
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(1)
- 返回值:1 表示移动成功,0 表示失败。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 5 6 7 8
(integer) 4
127.0.0.1:6379> SMOVE key1 key2 1
(integer) 1
127.0.0.1:6379> SMEMBERS key1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> SMEMBERS key2
1) "1"
2) "5"
3) "6"
4) "7"
5) "8"
如果我给 key1 里面再添加一个1,再把这个 1 移动给 key2 ~~ 会怎样?
127.0.0.1:6379> sadd key1 1
(integer) 1
127.0.0.1:6379> SMEMBERS key1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SMOVE key1 key2 1
(integer) 1
127.0.0.1:6379> SMEMBERS key1
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> SMEMBERS key2
1) "1"
2) "5"
3) "6"
4) "7"
5) "8"
6.SREM
- 将指定的元素从 set 中删除。
- 语法:
SREM key member [member ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), N 是要删除的元素个数.
- 返回值:本次操作删除的元素个数。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> SREM key 1
(integer) 1
127.0.0.1:6379> SREM key 3 4
(integer) 2
二、集合间操作
交集(inter)、并集(union)、差集(diff)的概念如图所示。
1.SREM
- 获取给定 set 的交集中的元素。
- 语法:
SINTER key [key ...] #此处每个key都对应一个集合~~
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最⼤的集合元素个数.
- 返回值:交集的元素。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTER key1 key2
1) "3"
2) "4"
2.SINTERSTORE
- 获取给定 set 的交集中的元素并保存到目标 set 中。
- 语法:
SINTERSTORE destination key [key ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N * M), N 是最⼩的集合元素个数. M 是最⼤的集合元素个数.
- 返回值:交集的元素个数。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTER key1 key2
1) "3"
2) "4"
127.0.0.1:6379> SINTERSTORE key3 key1 key2
(integer) 2
127.0.0.1:6379> SMEMBERS key3
1) "3"
2) "4"
3.SUNION
- 获取给定 set 的并集中的元素。
- 语法:
SUNION key [key ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:并集的元素。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTER key1 key2
1) "3"
2) "4"
127.0.0.1:6379> SINTERSTORE key3 key1 key2
(integer) 2
127.0.0.1:6379> SMEMBERS key3
1) "3"
2) "4"
127.0.0.1:6379> SUNION key1 key2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
4.SUNIONSTORE
- 获取给定 set 的并集中的元素并保存到⽬标 set 中。
- 语法:
SUNIONSTORE destination key [key ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:并集的元素个数。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTER key1 key2
1) "3"
2) "4"
127.0.0.1:6379> SINTERSTORE key3 key1 key2
(integer) 2
127.0.0.1:6379> SMEMBERS key3
1) "3"
2) "4"
127.0.0.1:6379> SUNION key1 key2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> SUNIONSTORE key4 key1 key2
(integer) 6
127.0.0.1:6379> SMEMBERS key4
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
5.SDIFF
- 获取给定 set 的差集中的元素。
- 语法:
SDIFF key [key ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:差集的元素。
- 示例:
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> sadd key1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd key2 3 4 5 6
(integer) 4
127.0.0.1:6379> SDIFF key1 key2
1) "1"
2) "2"
127.0.0.1:6379> SDIFF key2 key1
1) "5"
2) "6"
6.SDIFFSTORE
- 获取给定 set 的差集中的元素并保存到⽬标 set 中。
- 语法:
SDIFFSTORE destination key [key ...]
- 命令有效版本:1.0.0 之后
- 时间复杂度:O(N), N 给定的所有集合的总的元素个数.
- 返回值:差集的元素个数。
127.0.0.1:6379> SDIFF key1 key2
1) "1"
2) "2"
127.0.0.1:6379> SDIFF key2 key1
1) "5"
2) "6"
127.0.0.1:6379> SDIFFSTORE key5 key1 key2
(integer) 2
127.0.0.1:6379> SMEMBERS key5
1) "1"
2) "2"
三、命令小结
集合类型命令
四、编码方式
集合类型的内部编码有两种:
- **intset(整数集合):**当集合中的元素都是整数并且元素的个数⼩于 set-max-intset-entries 配置
(默认 512 个)时,Redis 会选⽤ intset 来作为集合的内部实现,从⽽减少内存的使⽤。
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> object encoding key
"intset"
- **hashtable(哈希表):**当集合类型⽆法满⾜ intset 的条件时,Redis 会使⽤ hashtable 作为集合
的内部实现。
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> sadd key 1 2 3 4
(integer) 4
127.0.0.1:6379> object encoding key
"intset"
127.0.0.1:6379> sadd key hello
(integer) 1
127.0.0.1:6379> object encoding key
"hashtable"
五、应用场景
集合类型比较典型的使用场景是标签(tag)。
例如 A 用户对娱乐、体育板块比较感兴趣,B 用户对历史、新闻比较感兴趣,这些兴趣点可以被抽象为标签。
有了这些数据就可以得到喜欢同⼀个标签的⼈,以及用户的共同喜好的标签,这些数据对于增强用户体验和用户黏度都⾮常有帮助。 例如⼀个电⼦商务网站会对不同标签的⽤⼾做不同的产品推荐。
1.给用户添加标签(使用set来保存用户的“标签”)
用户画像
分析出你这个人的一些特征,分析清楚特征之后,再投其所好~~ “千人千面”
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
sadd user:k:tags tag1 tag2 tag4
2.给标签添加用户
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
sadd tagk:users user:1 user:4 user:9 user:28
3.删除用户下的标签
srem user:1:tags tag1 tag5
...
4.删除标签下的用户
srem tag1:users user:1
srem tag5:users user:1
...
5.计算用户的共同兴趣标签
sinter user:1:tags user:2:tags