深入剖析Redis系列(八) - Redis数据结构之集合

栏目: 数据库 · 发布时间: 6年前

内容简介:集合(如图所示,集合返回结果为添加成功的

集合( set )类型也是用来保存多个 字符串元素 ,但和 列表类型 不一样的是,集合中 不允许有重复元素 ,并且集合中的元素是 无序的 ,不能通过 索引下标 获取元素。

深入剖析 <a href='https://www.codercto.com/topics/18994.html'>Redis</a> 系列(八) - Redis数据结构之集合

如图所示,集合 user:1:follow 包含着 "it""music""his""sports" 四个元素,一个 集合 最多可以存储 2 ^ 32 - 1 个元素。 Redis 除了支持 集合内增删改查 ,同时还支持 多个集合交集并集差集 。合理地使用好集合类型,能在实际开发中解决很多实际问题。

深入剖析Redis系列(八) - Redis数据结构之集合

其他文章

正文

1. 相关命令

1.1. 集合内的操作命令

1.1.1. 添加元素

sadd key element [element ...]

返回结果为添加成功的 元素个数 ,例如:

127.0.0.1:6379> exists myset
(integer) 0
127.0.0.1:6379> sadd myset a b c
(integer) 3
127.0.0.1:6379> sadd myset a b
(integer) 0
复制代码

1.1.2. 删除元素

srem key element [element ...]

返回结果为成功删除 元素个数 ,例如:

127.0.0.1:6379> srem myset a b
(integer) 2
127.0.0.1:6379> srem myset hello
(integer) 0
复制代码

1.1.3. 计算元素个数

scard key

scard时间复杂度O(1) ,它 不会遍历 集合所有元素,而是直接用 Redis内部 的变量,例如:

127.0.0.1:6379> scard myset
(integer) 1
复制代码

1.1.4. 判断元素是否在集合中

sismember key element

如果给定元素 element 在集合内返回 1 ,反之返回 0

127.0.0.1:6379> sismember myset c
(integer) 1
复制代码

1.1.5. 随机从集合返回指定个数元素

srandmember key [count]

[count]可选参数 ,如果不写默认为 1

127.0.0.1:6379> srandmember myset 2
1) "a"
2) "c"
127.0.0.1:6379> srandmember myset
"d"
复制代码

1.1.6. 从集合随机弹出元素

spop key

spop 操作可以从 集合随机弹出 一个元素,例如下面代码是一次 spop 后, 集合元素 变为 "d b a"

127.0.0.1:6379> spop myset
"c"
127.0.0.1:6379> smembers myset
1) "d"
2) "b"
3) "a"
复制代码

注意: Redis3.2 版本开始, spop 也支持 [count] 参数。

srandmemberspop 都是 随机 从集合选出元素,两者不同的是 spop 命令执行后, 元素 会从集合中 删除 ,而 srandmember 不会删除元素。

1.1.7. 获取所有元素

smembers key

下面代码获取集合 myset所有元素 ,并且 返回结果无序的

127.0.0.1:6379> smembers myset
1) "d"
2) "b"
3) "a"
复制代码

smemberslrangehgetall 都属于 比较重 的命令,如果 元素过多 存在 阻塞 Redis 的可能性,这时候可以使用 sscan 命令来完成。

1.2. 集合间的操作命令

现在有 两个集合 ,它们分别是 user:1:followuser:2:follow

127.0.0.1:6379> sadd user:1:follow it music his sports
(integer) 4
127.0.0.1:6379> sadd user:2:follow it news ent sports
(integer) 4
复制代码

1.2.1. 求多个集合的交集

sinter key [key ...]

下面的代码是求 user:1:followuser:2:follow 两个集合的 交集 ,返回结果是 sportsit

127.0.0.1:6379> sinter user:1:follow user:2:follow
1) "sports"
2) "it"
复制代码

1.2.2. 求多个集合的并集

suinon key [key ...]

下面的代码是求 user:1:followuser:2:follow 两个集合的 并集 ,返回结果是 sportsithisnewsmusicent

127.0.0.1:6379> sunion user:1:follow user:2:follow
1) "sports"
2) "it"
3) "his"
4) "news"
5) "music"
6) "ent"
复制代码

1.2.3. 求多个集合的差集

sdiff key [key ...]

下面的代码是求 user:1:followuser:2:follow 两个集合的 差集 ,返回结果是 musichis

127.0.0.1:6379> sdiff user:1:follow user:2:follow
1) "music"
2) "his"
复制代码

前面三个求 交集并集差集 的操作得到的结果,如图所示:

深入剖析Redis系列(八) - Redis数据结构之集合

1.2.4. 将交集、并集、差集的结果保存

集合间的运算在 元素较多 的情况下会 比较耗时 ,所以 Redis 提供了以下 三个命令原命令 + store )将 集合间交集并集差集 的结果保存在 destination key 中。

sinterstore destination key [key ...] suionstore destination key [key ...] sdiffstore destination key [key ...]

下面的操作会将 user:1:followuser:2:follow 两个集合交集结果 保存在 user:1_2:inter 中, user:1_2:inter 本身也是 集合类型

127.0.0.1:6379> sinterstore user:1_2:inter user:1:follow user:2:follow
(integer) 2
127.0.0.1:6379> type user:1_2:inter
set
127.0.0.1:6379> smembers user:1_2:inter
1) "it"
2) "sports"
复制代码

有关 集合常用命令 基本上就是这么多了,下表给出了 集合常用命令时间复杂度 ,开发人员可以根据自身需求进行选择。

深入剖析Redis系列(八) - Redis数据结构之集合

2. 内部编码

集合类型的 内部编码 有两种:

2.1. intset(整数集合)

当集合中的元素都是 整数元素个数 小于 set-max-intset-entries 配置(默认 512 个)时, Redis 会选用 intset 来作为 集合内部实现 ,从而 减少内存 的使用。

2.2. hashtable(哈希表)

当集合类型 无法满足 intset 的条件时, Redis 会使用 hashtable 作为集合的 内部实现

2.3. 具体示例

2.3.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.3.2. 内部编码为哈希

  • 元素个数 超过 512 个, 内部编码 变为 hashtable
127.0.0.1:6379> sadd setkey 1 2 3 4 5 6 ... 512 513
(integer) 513
127.0.0.1:6379> scard setkey
(integer) 513
127.0.0.1:6379> object encoding listkey
"hashtable"
复制代码
  • 当某个元素 不为整数 时, 内部编码 也会变为 hashtable
127.0.0.1:6379> sadd setkey a
(integer) 1
127.0.0.1:6379> object encoding setkey
"hashtable"
复制代码

有关集合类型的 内存优化 技巧,后面的文章会有专门的讲解。

3. 应用场景

3.1. 用户标签

集合类型比较典型的使用场景是 标签tag )。简单的举两个例子:

3.1.3. 娱乐新闻推荐

一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。

3.1.2. 电商人群分类

一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为网站带来更多的利益。

下面使用 集合类型 实现 标签功能

  • 给用户添加标签
sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
sadd user:k:tags tag1 tag2 tag4
...
复制代码
  • 给标签添加用户
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
sadd tagk:users user:1 user:2
...
复制代码

用户和 标签关系维护 应该在 一个事务内 执行,防止 部分命令失败 造成的 数据不一致 ,有关如何将 两个命令 放在 一个事务 中,后面会介绍 Lua 的使用。

  • 删除用户下的标签
srem user:1:tags tag1 tag5
...
复制代码
  • 删除标签下的用户
srem tag1:users user:1
srem tag5:users user:1
...
复制代码
  • 计算用户共同感兴趣的标签

可以使用 sinter 命令,来计算 用户共同感兴趣标签

sinter user:1:tags user:2:tags
复制代码

上面只是给出了使用 Redis 集合类型 实现 标签 的基本思路,实际上一个 标签系统 远比这个要 复杂 得多,不过 集合类型应用场景 通常为以下几种:

命令组合 应用场景
sadd Tagging(标签)
spop/srandmember Random item(生成随机数,比如抽奖)
sadd + sinter Social Graph(社交需求)

小结

本文介绍了 Redis 中的 集合 的 一些 基本命令 ,包括 集合内部的操作命令集合之间的操作命令 ,其次还介绍了 集合内部编码 转换和以 用户行为标签 为主的 应用场景


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

水平营销

水平营销

[美] 菲利普·科特勒、费尔南多・德・巴斯 / 陈燕茹 / 中信出版社 / 2005-1 / 25.00元

《水平营销》阐明了相对纵向营销而言的的水平营销的框架和理论。引入横向思维来作为发现新的营销创意的又一平台,旨在获得消费者不可能向营销研究人员要求或建议的点子。而这些点子将帮助企业在产品愈加同质和超竞争的市场中立于不败之地。 《水平营销》提到: 是什么创新过程导致加油站里开起了超市? 是什么创新过程导致取代外卖比萨服务的冷冻比萨的亮相? 是什么创新过程导致巧克力糖里冒出了玩具......一起来看看 《水平营销》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具