elasticsearch - Elasticsearch-聚合多层次结构

标签 elasticsearch full-text-search search-engine

我在提供具有多层次结构的文档的聚合搜索结果时遇到问题。简化的文档结构如下所示:

杂志标题(狩猎)->杂志年份(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/

相关文章:

elasticsearch - 删除Elasticsearch中的所有索引

Elasticsearch search_after,不使用 _id 作为 tie_breaker_field 吗?

laravel - 安装laravel-scout-elastic版本时出错

architecture - 使用 NLP API 创建客户自助服务?

performance - 为什么 PostgreSQL Text-Search GiST 索引比 GIN 索引慢这么多?

html - 搜索引擎是否支持角色属性?

node.js - 在 MongoDB 中搜索(来自 NodeJS)

elasticsearch - Elasticsearch范围查询对象列表

sql-server - 全文未索引 varbinary 列(使用 html)

seo - 改进词典的内部链接结构