使用Elasticsearch管理关系— Naukri Engineering

创建人: Lucky Sharma

资源

介绍

Elasticsearch是一个搜索引擎。 它提供了基于无模式JSON文档的分布式全文本搜索引擎。

众所周知,Elasticsearch是索引和搜索大量文档的出色产品。 它支持各种功能,例如术语和范围查询,全文本搜索以及对大型数据集的聚合,这些功能非常快速且强大。

它基于Lucene构建,Lucene是用Java编写的高性能,全功能的文本搜索引擎库。

当我们为数据建立索引时,世界几乎不像孤立存在的独立数据那样简单,在某些情况下,需要将其保留为关系数据。 有时,最好将数据规范化到子级中。

因为如果不对它进行非规范化,那么所有文档中都会有冗余数据。 最好的例子之一是,如果您拥有博客站点数据,那么您就不想在每个评论中重复博客文章的全部内容,因为这会大大增加索引数据的数量。

图。1

一种选择是将子文档放在父文档中,如图1所示。

这里的一个缺点是添加子文档将导致整个文档的重新索引。

如何对文档进行非规范化

Elasticsearch提供了两个有助于解决问题的概念:

  1. 嵌套文档/查询
  2. 父母与子女的关系。

我们将在“亲子关系”上进行更多讨论。

亲子关系

建立父子关系所需要做的就是指定哪种文档类型应作为子类型的父项。 在创建子类型之前,您必须在创建索引时或使用更新映射API进行此操作。

例如:这是我们在First Naukri中作为父子实现的非常基本的架构示例,其中父是学院,子是学生。

亲子索引与其他策略有何不同:

自Lucene 3.4版以来,就提供了关系支持。

有两种不同类型的关系:

  1. 索引时间加入。
  2. 查询时间加入

分度时间:

这是一个块索引,其中将一个文档块添加到索引中,并且父文件是最后一个块。

每个文档将获得按顺序分配的Lucene文档ID。

Lucene:IndexWriter#addDocuments()

但这带有一个条款,子代或父代的任何更改都将导致对整个文档块重新编制索引。

*段合并不会重新排序段中的文档。

在Elasticsearch中,这种类型的联接/关系显示为嵌套对象。

查询时间:

顾名思义,这是一个查询时间联接,它比较昂贵,但提供了广泛的灵活性。

它不需要任何块索引,因此没有这样的子句可以对所有父子项进行索引(如果它们中的任何一个发生了变化)。

查询时间期间,您可以从父索引搜索到子索引,反之亦然。

查询时间分两个阶段执行:

该查询将在子索引上执行,所有子ID均用于过滤父索引。 (在has_child查询的情况下)。

这种查询的先决条件是必须在父级分片中正确索引子级。

因此,如果parent(ID)未知,则必须采取特殊的预防措施来获取,修改和删除它们。

亲子关系行为类似于RDBMS中的外键关系,

但是这种关系有一些限制:

  1. 如果要定义子代,则需要类型的父代。
  2. 为了减少联网并提高性能,子代与父代之间的关系是通过分片完成的,而不是将其分布在所有群集上。

该查询会消耗大量内存,因为它需要您获取所有子ID。如果父母的数量较少,则建议使用has_parent查询。 Elasticsearch使用_parent字段构建了一个ID缓存,该缓存使父子查询/过滤器更快。

索引和搜索查询示例:

Elasticsearch在ram中保存父数据和子数据,并计算实时关系。

这两个文档现在都与“ Institute”父文档相关联,从而允许您使用特殊查询,例如:

  • 有上级查询:适用于上级文档并返回子级。
  • 有子查询:适用于子文档并返回父文档。
  • 热门子查询:执行查询并返回前X个匹配子项。

在多个子文档上进行子查询排序:

结果集将是来自BTECH或BE课程的学生名称为“ lucky sharma”的学院

如何/何时比其他策略更好

在这种策略中:

  • 子代与父代分开存储,但被路由到同一分片。 因此,父级/子级在读取/查询上的性能略低于嵌套。
  • 更新子文档不会影响父文档或其他任何子文档,这可能会节省大型文档的大量索引
  • 我们要保持所有的关系

使用亲子关系的缺点

不利的一面是,父母/子女的表现比嵌套的表现稍差。 子文档与父文档路由到相同的分片,因此它们仍将受益于分片级缓存和内存过滤。 但是它们并没有嵌套的快,因为它们不在同一Lucene块中并置。 还有一点更多的内存开销,因为Elasticsearch需要保留一个内存中的“联接表”来管理关系。

在Elasticsearch中实现亲子关系之前要记住的事情

  • 当Elasticsearch在内存中执行父子联接时,复杂的查询将减慢搜索速度。
  • 需要确定哪些实体需要成为父母,什么需要成为孩子。
  • 是否具有子实体和父实体,而不是作为嵌套对象。