2016-12-06 229 views
9

我正在尝试查找在多个方面都相同的数据条目。我目前做到这一点使用一个复杂的查询其巢汇总:在Elasticsearch中查找重复项目

{ 
    "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": {} } } } } } } } } } } } 

这个工程到一个程度,结果我得到的时候没有重复被发现是这个样子:

{ 
    "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个完整数据集在应用聚合之前,然后是一个(剩余的第四个字段)。然后我必须全部应用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的情况下,它必须为内存中的每个文档保存一个桶(只有一个文档)。即使只能找到几个双打,对于更大的数据集也无法完成。如果没有其他可行的办法,则需要人工将数据组分组。例如,可以通过在相关字段之外构建散列来创建16个子数据集,并使用最后4位将文档置于16个组上。然后可以分别处理每个组;双打必然会落入使用这种技术的一组。

但是独立于这些一般想法,ES API应该提供任何方式来通过聚合结果进行分页。可惜没有这样的选择(但)。

+0

在我看来,最好和正确的方法是在文档中创建一个新字段(当然,这意味着需要将数据重新索引到新索引中),该字段应包含您正在查找的字段组合。然后,在搜索时间,您可以在该单个字段上进行汇总。 –

+0

如果您连接不同的字段,最好在它们之间添加一些分隔符,因此您更确定多个字段的合并与其他字段的合并不同。(例如'test'+'ing'='testing'=>'test'+'#'+'ing'<>'testing') – rvheddeg

回答

0

可能在Logstash方案的工作是使用复制域的构想:

复制所有组合到一个单独的领域和Concat的他们:

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

聚集在新的领域。

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

我不知道,如果add_field支持数组(如果你看一下文档别人做)。如果没有,您可以尝试添加几个新字段并使用合并来只有一个字段。

如果你可以在索引时做到这一点,它肯定会更好。

你只需要

+0

当然,也可能是可行的,取决于我们所谈论的大小。在我的情况下,我担心突变过程可能需要相当长的时间,如果我需要不同的字段集合,我必须创建几个你建议的new_field版本。这可能会成为一个内存问题,在我的情况下: -/ – Alfe

+0

我认为你的答案只适用于Logstash情况。我没有使用Logstash,并希望解决我的问题,但是;-) – Alfe

+0

如何重新组合索引?如果您有10个字段,您可以将每个字段索引为正常的9倍,而该字段可能是未分析的字段。如果你不希望你可以考虑一个脚本字段放置这些值,但对于冗余索引字段,性能肯定会更好。 –

1

你最后的方法似乎是最好的一个组合(A_B),而不是所有的排列(A_B,B_A)。你可以update your elasticsearch settings如下:

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

我选择75%因为默认是60%,它是在你的elasticsearch 5.9gb和您的查询正在成为一种基于日志各地71.1%~6.3gb

circuit_breaking_exception: [request] Data too large, data for [<reused_arrays>] would be larger than limit of [6348236390/5.9gb]

最后indices.breaker.total.limit必须大于indices.breaker.fielddata.limit根据elasticsearch document

+0

请看我自己的答案,阅读为什么整个方法对于真正的大数据集不可行(因为我认为现在理解),所以向上推动一些技术限制并不是一个解决方案。 – Alfe