我在提供具有多层次结构的文档的聚合搜索结果时遇到问题。简化的文档结构如下所示:
杂志标题(狩猎)->杂志年份(1999)->杂志发行(II。)->页面(页面文本...)
每个级别的文档都通过属性“parentDocumentId” 映射到其父文档。
我已经准备了简单的查询,该查询对于只有2个级别的层次结构非常适用:
POST http://localhost:9200/my_index/document/_search?search_type=count&q=hunter
{
"query": {
"multi_match" : {
"query": "hunter",
"fields": [ "title", "text", "labels" ]
}
},
"aggregations": {
"my_agg": {
"terms": {
"field": "parentDocumentId"
}
}
}
}
此查询能够搜索页面文本,而不是给我成千上万个包含工作“猎人”的页面,而是返回文档的存储桶(由parentDocumentId聚合)。但是,这些存储桶仅表示包含这些页面的“杂志问题” 。
响应:
{
"took": 54,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 44,
"max_score": 0,
"hits": []
},
"aggregations": {
"my_agg": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 5,
"doc_count": 43
},
{
"key": 0,
"doc_count": 1
}
]
}
}
}
我需要的是能够以尽可能高的级别聚合搜索结果。这意味着,在这种特殊情况下,将在“杂志标题” 级别上进行汇总。这可以在elasticsearch查询之外(在我们的应用程序一侧)完成,但是正如我所看到的,它绝对应该在elasticsearch(性能和其他问题)中进行。
是否有人有类似的经验? Elasticsearch聚合是正确的使用方法吗?
每个想法都是受欢迎的。
谢谢
彼得
更新:
我们的映射如下所示:
{
"my_index": {
"mappings": {
"document": {
"properties": {
"dateIssued": {
"type": "date",
"format": "dateOptionalTime"
},
"documentId": {
"type": "long"
},
"filter": {
"properties": {
"geo_bounding_box": {
"properties": {
"issuedLocation": {
"properties": {
"bottom_right": {
"properties": {
"lat": {
"type": "double"
},
"lon": {
"type": "double"
}
}
},
"top_left": {
"properties": {
"lat": {
"type": "double"
},
"lon": {
"type": "double"
}
}
}
}
}
}
}
}
},
"issuedLocation": {
"type": "geo_point"
},
"labels": {
"type": "string"
},
"locationLinks": {
"type": "geo_point"
},
"parentDocumentId": {
"type": "long"
},
"query": {
"properties": {
"match_all": {
"type": "object"
}
}
},
"storedLocation": {
"type": "geo_point"
},
"text": {
"type": "string"
},
"title": {
"type": "string"
},
"type": {
"type": "string"
}
}
}
}
}
}
这意味着我们对所有类型的文档使用1个映射。我们正在为书籍,报纸和其他媒体编制索引。这就是说,有时页面集只有一个父级,而有时有时页面级以上会有多个父级。
为了区分文档的类型,有一个属性“type” 。
在为顶层索引(这些索引尤其包含书中的元数据)时,我们将“text”属性留空,始终使用parentDocumentId指定文档的父级。顶层文档的parentDocumentId设置为0。索引最低层的文档(页面)时,我们仅为索引文档提供text属性和parentDocumentId。
使用的链接与经典的一对多映射非常相似(杂志有很多年,有很多问题,有很多页面)。
您也可以说,我们已经在Elasticsearch中展平了嵌套文档,但是原因是存在多种文档类型,它们可以具有不同的层次结构级别。
最佳答案
您需要重新考虑数据建模。本质上,您需要对数据进行联接,此外,联接还需要跨任意深度的层次结构。即使在关系数据库中,甚至在像Elasticsearch这样的全文搜索引擎中,也是如此。
Elasticsearch确实支持几个联接。您可以使用嵌套的文档-嵌套了所有子文档的单个文档。在您的情况下,这显然不理想。
您可以使用parent-child relationship功能,该功能使您始终可以引用父文档来单独索引(子)文档。在下面,该功能使用Lucene的blockjoin。但是,要聚合层次结构,您必须显式指定连接-列出所有中间步骤。您希望始终按最可用的文档进行汇总,但是每次(一次杂志,另一次杂志收藏或出版商)的级别可能都不同。
我会考虑用指向最顶层文档的字段为每个文档建立索引。然后,您可以轻松地通过该字段进行汇总。这将意味着预先计算要执行的复杂聚合的一部分,但这将导致快速聚合,并且更新也不会很麻烦。这一切都取决于您的数据源,您如何想象它会发生变化,需要进行哪些更新以及其他查询。
这篇博客文章也可以帮助您一些指导:https://www.elastic.co/blog/managing-relations-inside-elasticsearch
关于elasticsearch - Elasticsearch-聚合多层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30026860/