⼲货Elasticsearch多表关联设计指南
版权声明:本⽂为博主原创⽂章,未经博主允许不得转载。转载请务必加上原作者:铭毅天下,原⽂地址:
Elasticsearch多表关联问题是讨论最多的问题之⼀,如:博客和评论的关系,⽤户和爱好的关系。
多表关联通常指:1对多,或者多对多。
本⽂以星球问题会出发点,引申出ES多表关联认知,分析了4种关联关系的适⽤场景、优点、缺点,
希望对你有所启发,为你的多表关联⽅案选型、实战提供帮助。
1、抛出问题
1.1 星球典型问题
1.2 社区典型问题
1.3 QQ典型问题
关系型数据库中的多表之间的关联查询,ES中有什么好的解决⽅案?
如果我把关联关系的表迁移到ES中放到⼀个type下,⽂档结构除了对象之间的嵌套还有什么好的解决⽅案?
2、基础认知
2.1 关系型数据库
关系数据库是专门为关系设计的,有如下特点:
可以通过主键唯⼀地标识每个实体(如Mysql中的⾏)。
实体 规范化 。唯⼀实体的数据只存储⼀次,⽽相关实体只存储它的主键。只能在⼀个具体位置修改这个实体的数据。
实体可以进⾏关联查询,可以跨实体搜索。
⽀持ACID特性,即:单个实体的变化是 原⼦的 , ⼀致的 , 隔离的 , 和 持久的 。
⼤多数关系数据库⽀持跨多个实体的 ACID 事务。
关系型数据库的缺陷:
第⼀:全⽂检索有限的⽀持能⼒。 这点,postgresql已部分⽀持,但相对有限。
第⼆:多表关联查询的耗时很长,甚⾄不可⽤。之前系统开发中使⽤过Mysql8个表做关联查询,⼀次查询等待⼗分钟+,基本不可⽤。
2.2 Elasticsearch
Elasticsearch ,和⼤多数 NoSQL 数据库类似,是扁平化的。索引是独⽴⽂档的集合体。 ⽂档是否匹配搜索请求取决于它是否包含所有的所需信息和关联程度。
Elasticsearch 中单个⽂档的数据变更是满⾜ACID的, ⽽涉及多个⽂档时则不⽀持事务。当⼀个事务部分失败时,⽆法回滚索引数据到前⼀个状态。
扁平化有以下优势:
1. 索引过程是快速和⽆锁的。
2. 搜索过程是快速和⽆锁的。
3. 因为每个⽂档相互都是独⽴的,⼤规模数据可以在多个节点上进⾏分布。
2.3 Mysql VS Elasticsearch
mysql才擅长关系管理,⽽ES擅长的是检索。
Medcl也曾强调:“如果可能,尽量在设计时使⽤扁平的⽂档模型。” Elasticsearch的关联存储、检索、聚合操作势必会有⾮常⼤的性能开销。
3 Elasticsearch关联关系如何存储
关联关系仍然⾮常重要。某些时候,我们需要缩⼩扁平化和现实世界关系模型的差异。
以下四种常⽤的⽅法,⽤来在 Elasticsearch 中进⾏关联数据的管理:
3.1 应⽤端关联
这是普遍使⽤的技术,即在应⽤接⼝层⾯来处理关联关系。
针对星球问题实践,
1. 存储层⾯:独⽴两个索引存储。
2. 实际业务层⾯分两次请求:
第⼀次查询返回:Top5中⽂姓名和成绩;
根据第⼀次查询的结果,第⼆次查询返回:Top5中⽂姓名和英⽂姓名;
将第⼀次查询结果和第⼆次查询结果组合后,返回给⽤户。
即:实际业务层⾯是进⾏了两次查询,统⼀返回给⽤户。⽤户是⽆感知的。
适⽤场景:数据量少的业务场景。
优点:数据量少时,⽤户体验好。
缺点:数据量⼤,两次查询耗时肯定会⽐较长,影响⽤户体验。
引申场景:关系型数据库和ES 结合,各取所长。将关系型数据库全量同步到 ES 存储,不做冗余存储。
如前所述:ES 擅长的是检索,⽽ MySQL 才擅长关系管理。所以可以考虑⼆者结合,使⽤ ES 多索引建⽴相同的别名,针对别名检索到对应 ID 后再回 MySQL 查询,业务层⾯通过关联 ID join 出需要的数据。
3.2 宽表冗余存储
对应于官⽅⽂档中的“Data denormalization”,官⽅直接翻译为:“⾮规范化你的数据”,总感觉规范化是什么⿁,不好理解。
通俗解释就是:冗余存储,对每个⽂档保持⼀定数量的冗余数据可以在需要访问时避免进⾏关联。
这点通过logstash 同步关联数据到ES时,通常会建议:先通过视图对Mysql数据做好多表关联,然后同步视图数据到ES。此处的视图就是宽表。
针对星球问题实践:姓名、英⽂名、成绩两张表合为⼀张表存储。
适⽤场景:⼀对多或者多对多关联。
优点:速度快。因为每个⽂档都包含了所需的所有信息,当这些信息需要在查询进⾏匹配时,并不需要进⾏昂贵的关联操作。
缺点:索引更新或删除数据,应⽤程序不得不处理宽表的冗余数据;
由于冗余存储,导致某些搜索和聚合操作可能⽆法按照预期⼯作。
3.3 嵌套⽂档(Nested )存储Nested类型是ES Mapping定义的集合类型之⼀,它是⽐object类型更NB的⽀持独⽴检索的类型。
举例:有⼀个⽂档描述了⼀个帖⼦和⼀个包含帖⼦上所有评论的内部对象评论。可以借助 Nested 实现。
实践注意1:当使⽤嵌套⽂档时,使⽤通⽤的查询⽅式是⽆法访问到的,必须使⽤合适的查询⽅式(nested query、nested filter、nested facet等),很多场景下,使⽤嵌套⽂档的复杂度在于索引阶段对关联关系的组织拼装。
推荐实践:
实践注意2:
适⽤场景:1 对少量,⼦⽂档偶尔更新、查询频繁的场景。
如果需要索引对象数组并保持数组中每个对象的独⽴性,则应使⽤嵌套 Nested 数据类型⽽不是对象 Oject 数据类型。
mysql帮助文档优点:nested⽂档可以将⽗⼦关系的两部分数据(举例:博客+评论)关联起来,可以基于nested类型做任何的查询。
缺点:查询相对较慢,更新⼦⽂档需要更新整篇⽂档。
3.4 ⽗⼦⽂档存储注意:6.X之前的版本的⽗⼦⽂档存储在相同索引的不同type中。⽽6.X 之上的版本,单索引下已不存在多type 的概念。⽗⼦⽂档Join的都是基于相同索引相同type实现的。
Join类型是ES Mapping定义的类型之⼀,⽤于在同⼀索引的⽂档中创建⽗/⼦关系。 关系部分定义⽂档中的⼀组可能关系,每个关系是⽗名称和⼦名称。
实践参考:适⽤场景:⼦⽂档数据量要明显多于⽗⽂档的数据量,存在1 对多量的关系;⼦⽂档更新频繁的场景。
举例:1 个产品和供应商之间是1对N的关联关系。
当使⽤⽗⼦⽂档时,使⽤has_child 或者has_parent做⽗⼦关联查询。
优点:⽗⼦⽂档可独⽴更新。
缺点:维护Join关系需要占据部分内存,查询较Nested更耗资源。
4
⼩结sted_fields.limit 缺省值是50。即:⼀个索引中最⼤允许拥有50个nested 类型的数据。sted_objects.limit 缺省值是10000。即:1个⽂档中所有nested 类型json 对象数据的总量是10000。
1
2
1. 在Elasticsearch开发实战中对于多表关联的设计要突破关系型数据库设计的思维定式。
2. 不建议在es做join操作,parent-child能实现部分功能,但是它的开销⽐较⼤,如果可能,尽量在设计时使⽤扁平的⽂档模型。
3. 尽量将业务转化为没有关联关系的⽂档形式,在⽂档建模处多下功夫,以提升检索效率。
4. Nested&Join⽗⼦⽂选型必须考虑性能问题。 nested 类型检索使得检索效率慢⼏倍,⽗⼦Join 类型检索会使得检索效率慢⼏百倍。
以上内容,实际官⽅⽂档都有明确的描述。我把内容加上⾃⼰的理解,作了精炼和解读。
再次强调:第⼀⼿资料的重要性。但本着“再显⽽易见的道理,也有N多⼈不知道”的原则,⼀定要读英⽂官⽅⽂档,加深认知理解。Elasticsearch多表关联你是如何做的呢?欢迎留⾔写下您的思考。
参考:
[1]
[2] rockybean 教程

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。