在Elasticsearch

时间:2016-12-06 15:45:14

标签: search elasticsearch nested duplicates aggregate

我正在尝试在我的数据中找到在多个方面相同的条目。我目前使用嵌套聚合的复杂查询来执行此操作:

{
  "size": 0, 
  "aggs": { 
    "duplicateFIELD1": { 
      "terms": { 
        "field": "FIELD1", 
        "min_doc_count": 2 },
      "aggs": { 
        "duplicateFIELD2": { 
          "terms": { 
            "field": "FIELD2", 
            "min_doc_count": 2 },
          "aggs": {
            "duplicateFIELD3": {
              "terms": {
                "field": "FIELD3",
                "min_doc_count": 2 },
              "aggs": {
                "duplicateFIELD4": {
                  "terms": {
                    "field": "FIELD4",
                    "min_doc_count": 2 },
                  "aggs": {
                    "duplicate_documents": { 
                      "top_hits": {} } } } } } } } } } } }

这在某种程度上起作用,因为当找到 no 重复项时,我得到的结果如下所示:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "hits" : {
    "total" : 27524067,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "duplicateFIELD1" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 27524027,
      "buckets" : [
        {
          "key" : <valueFromField1>,
          "doc_count" : 4,
          "duplicateFIELD2" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : <valueFromField2>,
                "doc_count" : 2,
                "duplicateFIELD3" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : <valueFromField3>,
                      "doc_count" : 2,
                      "duplicateFIELD4" : {
                        "doc_count_error_upper_bound" : 0,
                        "sum_other_doc_count" : 0,
                        "buckets" : [ ]
                      }
                    }
                  ]
                }
              },
              {
                "key" : <valueFromField2>,
                "doc_count" : 2,
                "duplicateFIELD3" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : <valueFromField3>,
                      "doc_count" : 2,
                      "duplicateFIELD4" : {
                        "doc_count_error_upper_bound" : 0,
                        "sum_other_doc_count" : 0,
                        "buckets" : [ ]
                      }
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "key" : <valueFromField1>,
          "doc_count" : 4,
          "duplicateFIELD2" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : <valueFromField2>,
                "doc_count" : 2,
                "duplicateFIELD3" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : <valueFromField3>,
                      "doc_count" : 2,
                      "duplicateFIELD4" : {
                        "doc_count_error_upper_bound" : 0,
                        "sum_other_doc_count" : 0,
                        "buckets" : [ ]
                      }
                    }
                  ]
                }
              },
              {
                "key" : <valueFromField2>,
                "doc_count" : 2,
                "duplicateFIELD3" : {
                  "doc_count_error_upper_bound" : 0,
                  "sum_other_doc_count" : 0,
                  "buckets" : [
                    {
                      "key" : <valueFromField3>,
                      "doc_count" : 2,
                      "duplicateFIELD4" : {
                        "doc_count_error_upper_bound" : 0,
                        "sum_other_doc_count" : 0,
                        "buckets" : [ ]
                      }
                    }
                  ]
                }
              }
            ]
          }
        },
        ...

我正在跳过一些看起来非常相似的输出。

我现在可以浏览这个复杂的深层嵌套数据结构,发现所有这些嵌套存储桶中都没有存储任何文档。但这看起来相当麻烦。我想可能有更好(更直接)的方式。

此外,如果我想检查四个以上的字段,这个嵌套的结构将会增长,增长和增长。所以它不能很好地扩展,我想避免这种情况。

我可以改进我的解决方案,以便获得所有重复文件的简单列表吗? (也许那些彼此重复的东西以某种方式组合在一起。)或者是否有一种完全不同的方法(例如没有聚合),它没有我在这里描述的缺点?

编辑:我发现了一种使用ES here脚本功能的方法,但在我的ES版本中,这只返回一条错误消息。也许有人可以向我指出如何在ES 5.0中做到这一点?到目前为止,我的试验没有奏效。

编辑:我找到了一种方法,可以使用现代方法(语言“无痛”)使用脚本:

{
  "size": 0,
  "aggs": {
    "duplicateFOO": {
      "terms": {
        "script": {
          "lang": "painless",
          "inline": "doc['FIELD1'].value + doc['FIELD2'].value + doc['FIELD3'].value + doc['FIELD4'].value"
        },                   
        "min_doc_count": 2
      }                        
    }                         
  }
}

这似乎适用于非常少量的数据,并导致实际数据量(circuit_breaking_exception[request] Data too large, data for [<reused_arrays>] would be larger than limit of [6348236390/5.9gb])出错。关于如何解决这个问题的任何想法?可能调整ES的某些配置以使其使用更大的内部缓冲区或类似的?

似乎没有一个适当的解决方案可以避免以一般方式嵌套。

幸运的是,我的四个领域中有三个领域的价值范围非常有限;第一个只能是1或2,第二个可以是1,2或3,第三个可以是1,2,3或4.由于这些只有24种组合,我现在可以过滤掉一个完整的第24个应用聚合之前的数据集,然后是 one (剩余的第四个字段)。然后,我必须将所有动作应用24次(上述三个有限字段的每个组合一次),但这比一次处理完整数据集更可行。

我现在发送的查询(即24个查询中的一个)看起来像这样:

{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        { "match": { "FIELD1": 2 } },
        { "match": { "FIELD2": 3 } },
        { "match": { "FIELD3": 4 } } ] } },
  "aggs": {
    "duplicateFIELD4": {
      "terms": {
        "field": "FIELD4",
        "min_doc_count": 2 } } } }

这个结果当然不再嵌套了。但是,如果多个字段包含较大范围的任意值,则无法完成此操作。

我还发现,如果必须完成嵌套,那么值范围最大的字段(例如只有两个值,如“1或2”)应该在最里面,而且最大的值范围应该是最外层的。这大大提高了性能(但在我的情况下仍然不够)。做错了会让你最终得到一个无法使用的查询(几小时内没有响应,最后是服务器端的内存不足)。

我现在认为正确聚合是解决像我这样的问题的关键。使用脚本具有平坦的桶列表(如我的问题中所述)的方法必然会使服务器过载,因为它无法以任何方式分发任务。在根本没有找到double的情况下,它必须为内存中的每个文档保存一个桶(其中只有一个文档)。即使只能找到几个双打,也无法对较大的数据集进行此操作。如果没有别的办法,就需要人为地将数据集拆分成组。 E. g。一个人可以通过构建相关字段中的散列来创建16个子数据集,并使用最后4位将文档放入16个组中。然后可以单独处理每个组;使用这种技术,双打必然会分成一组。

但是,与这些一般性的想法无关,ES API应该提供任何手段来对聚合结果进行分页。遗憾的是,还没有这样的选择。

2 个答案:

答案 0 :(得分:1)

你的最后一种方法似乎是最好的方法。你可以update your elasticsearch settings如下:

indices.breaker.request.limit: "75%"
indices.breaker.total.limit: "85%"

我选择了75%,因为默认值为60%且弹性搜索中的5.9gb~6.3gb,而您的查询正变为基于71.1%的{​​{1}} circuit_breaking_exception: [request] Data too large, data for [<reused_arrays>] would be larger than limit of [6348236390/5.9gb]在你的日志上。

  

indices.breaker.total.limit

根据elasticsearch document,最后indices.breaker.fielddata.limit必须大于config/initializers/simple_form.rb

答案 1 :(得分:0)

可能在Logstash方案中有效的想法是使用复制字段:

将所有组合复制到单独的字段并连接它们:

mutate {
  add_field => {
    "new_field" => "%{oldfield1} %{oldfield2}"
  }
}

聚合新领域。

看看这里:https://www.elastic.co/guide/en/logstash/current/plugins-filters-mutate.html

我不知道add_field是否支持数组(如果您查看文档,其他人也会这样做)。如果不是,您可以尝试添加几个新字段并使用merge只有一个字段。

如果你能在索引时这样做,那肯定会更好。

您只需要组合(A_B)而非所有排列(A_B,B_A)