Elasticsearch - 聚合多级层次结构

时间:2015-05-04 09:34:50

标签: elasticsearch full-text-search search-engine

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

杂志标题(狩猎) - >杂志年(1999年) - >杂志问题(II。) - >页面(页面文字......)

每个级别的od文档都按属性“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"
         }
      }
  }
}

此查询能够搜索页面文本,而不是给我数千个包含工作的页面“hunter”返回文档的存储桶(由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中进行(性能和其他问题)。

是否有人有类似聚合的经验?弹性搜索聚合是正确的使用方法吗?

欢迎任何想法。

由于 彼得

更新 我们的映射看起来像这样:

{
   "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中展平了嵌套文档,但原因是,有多种文档类型,可以有不同级别的层次结构

1 个答案:

答案 0 :(得分:1)

您需要重新考虑数据建模。实质上,您需要对数据进行连接,而且连接需要在任意深层次结构上进行。即使在关系数据库中,这也是一个问题,更不用说像Elasticsearch这样的全文搜索引擎。

Elasticsearch确实支持几个连接。您可以使用嵌套文档 - 嵌套了所有子文件的单个文档。在你的情况下,这显然不太理想。

您可以使用parent-child relationship功能,该功能可让您单独索引(子)文档,并始终引用其父级。在下面,该功能使用Lucene的blockjoin。但是,要在层次结构上聚合,您必须显式指定连接 - 列出所有中间步骤。您希望始终按最顶层的可用文档进行汇总,但每次都可以是不同的级别(一次是杂志,另一次是杂志收藏或者是出版商)。

我会考虑使用指向最顶层文档的字段为每个doc编制索引。然后,您可以轻松地按该字段进行汇总。这将意味着预先计算您想要执行的复杂聚合的一部分,但这会导致快速聚合和更新也不会非常痛苦。这一切都取决于您的数据来源,您想象它将如何变化,您需要做什么更新和其他查询。

此博文可能对您有所帮助:https://www.elastic.co/blog/managing-relations-inside-elasticsearch