0、题记
Elasticsearch多表关联问题是讨论最多的问题之一,如:博客和评论的关系,用户和爱好的关系。html
多表关联一般指:1对多,或者多对多关系在ES中的呈现。mysql
本文以星球问题为出发点,引伸出ES多表关联认知,分析了4种关联关系的适用场景、优势、缺点。sql
但愿对你有所启发,为你的多表关联方案选型、实战提供帮助。数据库
一、抛出问题
1.1 星球典型问题
1.2 社区典型问题
1.3 QQ群典型问题
关系型数据库中的多表之间的关联查询,ES中有什么好的解决方案?
若是我把关联关系的表迁移到ES中放到一个type下,文档结构除了对象之间的嵌套还有什么好的解决方案?json
二、基础认知
2.1 关系型数据库
关系数据库是专门为关系设计的,有以下特色:数组
能够经过主键惟一地标识每一个实体(如Mysql中的行)。app
实体 规范化 。惟一实体的数据只存储一次,而相关实体只存储它的主键。只能在一个具体位置修改这个实体的数据。数据库设计
实体能够进行关联查询,能够跨实体搜索。elasticsearch
支持ACID特性,即:单个实体的变化是 原子的 , 一致的 , 隔离的 , 和 持久的 。ide
大多数关系数据库支持跨多个实体的 ACID 事务。
关系型数据库的缺陷:
第一:全文检索有限的支持能力。 这点,postgresql已部分支持,但相对有限。
第二:多表关联查询的耗时很长,甚至不可用。以前系统开发中使用过Mysql8个表作关联查询,一次查询等待十分钟+,基本不可用。
2.2 Elasticsearch
Elasticsearch ,和大多数 NoSQL 数据库相似,是扁平化的。索引是独立文档的集合体。 文档是否匹配搜索请求取决于它是否包含全部的所需信息和关联程度。
Elasticsearch 中单个文档的数据变动是知足ACID的, 而涉及多个文档时则不支持事务。当一个事务部分失败时,没法回滚索引数据到前一个状态。
扁平化有如下优点:
索引过程是快速和无锁的。
搜索过程是快速和无锁的。
由于每一个文档相互都是独立的,大规模数据能够在多个节点上进行分布。
2.3 Mysql VS Elasticsearch
mysql才擅长关系管理,而ES擅长的是检索。
Medcl也曾强调:“若是可能,尽可能在设计时使用扁平的文档模型。” Elasticsearch的关联存储、检索、聚合操做势必会有很是大的性能开销。
3 Elasticsearch关联关系如何存储
关联关系仍然很是重要。某些时候,咱们须要缩小扁平化和现实世界关系模型的差别。
如下四种经常使用的方法,用来在 Elasticsearch 中进行关联数据的管理:
3.1 应用端关联
这是广泛使用的技术,即在应用接口层面来处理关联关系。
针对星球问题实践,
存储层面:独立两个索引存储。
实际业务层面分两次请求:
第一次查询返回: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等),不少场景下,使用嵌套文档的复杂度在于索引阶段对关联关系的组织拼装。
推荐实践:干货 | Elasticsearch Nested类型深刻详解
实践注意2:
index.mapping.nested_fields.limit 缺省值是50。
即:一个索引中最大容许拥有50个nested类型的数据。
index.mapping.nested_objects.limit 缺省值是10000。
即:1个文档中全部nested类型json对象数据的总量是10000。
适用场景:1 对少许,子文档偶尔更新、查询频繁的场景。
若是须要索引对象数组并保持数组中每一个对象的独立性,则应使用嵌套 Nested 数据类型而不是对象 Oject 数据类型。
优势:nested文档能够将父子关系的两部分数据(举例:博客+评论)关联起来,能够基于nested类型作任何的查询。
缺点:查询相对较慢,更新子文档须要更新整篇文档。
3.4 父子文档存储
注意:6.X以前的版本的父子文档存储在相同索引的不一样type中。而6.X之上的版本,单索引下已不存在多type的概念。父子文档Join的都是基于相同索引相同type实现的。
Join类型是ES Mapping定义的类型之一,用于在同一索引的文档中建立父/子关系。 关系部分定义文档中的一组可能关系,每一个关系是父名称和子名称。
实践参考:Elasticsearch 6.X 新类型Join深刻详解
适用场景:子文档数据量要明显多于父文档的数据量,存在1 对多量的关系;子文档更新频繁的场景。
举例:1 个产品和供应商之间是1对N的关联关系。
当使用父子文档时,使用has_child 或者has_parent作父子关联查询。
优势:父子文档可独立更新。
缺点:维护Join关系须要占据部份内存,查询较Nested更耗资源。
4 小结
在Elasticsearch开发实战中对于多表关联的设计要突破关系型数据库设计的思惟定式。
不建议在es作join操做,parent-child能实现部分功能,可是它的开销比较大,若是可能,尽可能在设计时使用扁平的文档模型。
尽可能将业务转化为没有关联关系的文档形式,在文档建模处多下功夫,以提高检索效率。
Nested&Join父子文选型必须考虑性能问题。 nested 类型检索使得检索效率慢几倍,父子Join 类型检索会使得检索效率慢几百倍。
以上内容,实际官方文档都有明确的描述。我把内容加上本身的理解,做了精炼和解读。
再次强调:第一手资料的重要性。但本着“再显而易见的道理,也有N多人不知道”的原则,必定要读英文官方文档,加深认知理解。
Elasticsearch多表关联你是如何作的呢?欢迎留言写下您的思考。
参考:
[1] https://www.elastic.co/guide/en/elasticsearch/guide/current/relations.html[2] rockybean 教程