ES中的数据关联

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES中的数据关联相关的知识,希望对你有一定的参考价值。

参考技术A

对于solr来说是无法做两个collection之间的关联的,es是否可以做到类似于表的join关联那,这就是本篇需要研究的内容,

主要参考内容是官方文档。

先说下结论,如果不做特殊处理,es是无法完成类似与表Join的关联查询的。

官网里面有几种支持关联查询的办法:

可以看下map信息如下:

实际在es内,已经将user下面的id和name进行了扁平化处理,可以通过如下的方式查询:

优点:查询速度非常快,缺点是存在数据的冗余。

在ES中,对单个文档的增删改都是原子操作,有时候为了方便我们将实体和它相关的明细是放在一个文档中存储的。比如论坛发的帖子和它的回复信息。

其实和冗余对象有点类似,但是如果只是做查询会发现有问题,因为es扁平处理之后:

tilte、body、tags被称为父文档或根文档。

这样数组内之间是没有顺序关系的,这就导致了后面的查询仍然可以查到数据,嵌套对象是为了解决这个问题的,先看下普通的对象:

嵌套对象,上面的例子是没有定义map的情况直接发送数据,comments被定义为object,失去了数组内的顺序关系,如果先定义了nested对象,则如下:

再次发送相同的数据:

再次发起查询:

为什么查不到,是因为nested对象有自己特定的语法如下:

score_mode:表示嵌套文档的最高得分纳入到根文档的计算之中。
嵌套模型的缺点如下:

当对嵌套文档做增加、修改或者删除时,整个文档都要重新被索引。嵌套文档越多,这带来的成本就越大。
查询结果返回的是整个文档,而不仅仅是匹配的嵌套文档。尽管目前有计划支持只返回根文档中最佳匹配的嵌套文档,但目前还不支持。

父子对象是最类似与表join的对象,父子关系的对象分别位于不同的文档中,做到了很好的隔离。
有以下优点:
1)更新父文档或子文档时候,另一方不受影响。
2)创建和删除子文档,父文档不受到影响。
3)子文档可以作为独立的结果单独返回。

缺点是:
1)父文档和子文档必须存在同一个shard中。
2)貌似只能是同一个index的两个type(对于es6.x版本只能支持一个type,如何处理,目前还未看到)

原理:
Elasticsearch 维护了一个父文档和子文档的映射关系,得益于这个映射,父-子文档关联查询操作非常快。
但是这个映射也对父-子文档关系有个限制条件:父文档和其所有子文档,都必须要存储在同一个分片中。
父-子文档ID映射存储在 Doc Values 中。当映射完全在内存中时, Doc Values 提供对映射的快速处理能力,
另一方面当映射非常大时,可以通过溢出到磁盘提供足够的扩展能力
如何建立父子映射:
建立父-子文档映射关系时只需要指定某一个文档 type 是另一个文档 type 的父亲。 该关系可以在如下两个时间点设置:
1)创建索引时;
2)在子文档 type 创建之前更新父文档的 mapping。
举例来说,对于公司和员工之间存在着类似的关系,即可以将公司信息看成员工信息的父文档。

如下:

父子文档的创建
1)对于父对象来说,它是不知道有多少个子对象的,所以按照一般的对象创建方法即可。
2)子对象创建方法:

父文档 ID 有两个作用:创建了父文档和子文档之间的关系,并且保证了父文档和子文档都在同一个分片上。

这里面的父ID london 会作为路由的依据,这样子对象就会路由到父文档同一个shard上。
在执行单文档的请求时需要指定父文档的 ID,单文档请求包括:通过 GET 请求获取一个子文档;创建、更新或删除一个子文档。
而执行搜索请求时是不需要指定父文档的ID,这是因为搜索请求是向一个索引中的所有分片发起请求,而单文档的操作是只会向存储该文档的分片发送请求。
因此,如果操作单个子文档时不指定父文档的 ID,那么很有可能会把请求发送到错误的分片上。

父文档的 ID 应该在 bulk API 中指定

通过子文档查询父文档
查询80后所在的公司信息:

查询至少两个员工的公司:

通过父文档查询子文档

每个子文档都保存了父文档的ID。

以上是关于ES中的数据关联的主要内容,如果未能解决你的问题,请参考以下文章

ES6中的类

ES6中的类

ES索引和分片

Elasticsearch es join 多表关联如何设计

ES中mapping是什么,es中的数据类型

【Tableau】Tableau中的数据关联(联接)