如何删除搜索发现中的重复项

时间:2019-07-02 13:32:37

标签: elasticsearch kibana

我在kibana的Discovers搜索栏中的某些文档字段中搜索到一些重复的结果,我希望每次重复都获得一个唯一的文档。因为我开始使用它,所以我不知道如何使用查询dls来执行此操作。但我需要这样的东西:

任何搜索:

  Doc 1 {log: '0701143900', name: '5018', date: '2019/07/01 14:37:41:796'}
  Doc 2 {log: '0701143900', name: '5018', date: '2019/07/01 14:37:41:796'}
  Doc 3 {log: '0701143900', name: '5018', date: '2019/07/01 14:37:41:796'}
  Doc 4 {log: '0701125212', name: '5018', date: '2019/07/01 12:44:58:595'}
  Doc 5 {log: '0701125212', name: '5018', date: '2019/07/01 12:44:58:595'}
  Doc 6 {log: '0701125212', name: '5018', date: '2019/07/01 12:44:58:595'}

在dsl查询之后,我可以看到此结果(按日期字段的重复数据删除结果)

Doc 3 {log: '0701143900', name: '5018', date: '2019/07/01 14:37:41:796'}
Doc 4 {log: '0701125212', name: '5018', date: '2019/07/01 12:44:58:595'}

(可以是任何文档编号,但没有重复的文档编号)

1 个答案:

答案 0 :(得分:0)

在Elasticsearch中,并没有您要查找的SELECT ... DISTINCT操作类型,但是我们可以接近(有一些警告)。

注意:以下所有内容均在ES 6.8.1上进行了测试,但应该可以追溯到ES 2.x以及直到7.x为止。

有效地,您可以结合两件事:

  1. 无论您的唯一性标准是什么,terms aggregation(如果log字段足以声明唯一性,这将很容易。如果是字段的某种组合,则将获得nominally trickier with scripting且性能明显下降)
  2. 一个top hits aggregation,可从术语汇总的每个存储区中返回一个匹配项

在Elasticsearch中...

假设:

  • 您的日志在某个索引中(例如,名为logs-我在本地将您的记录编入名为logs-2019.07.01的索引中,并别名为logs
  • log字段进行了keyword分析(允许对其进行汇总)
POST /logs/_search
{
  "size": 0,
  "aggs": {
    "unique_logs": {
      "terms": {
        "field": "log",
        "size": 10
      },
      "aggs": {
        "docs": {
          "top_hits": {
            "size": 1
          }
        }
      }
    }
  }
}

这将最多返回10条唯一记录

{
  "took" : 2,
  ...
  "aggregations" : {
    "unique_logs" : {
      ...
      "buckets" : [
        {
          "key" : "0701125212",
          "doc_count" : 3,
          "docs" : {
            "hits" : {
              "total" : 3,
              "max_score" : 1.0,
              "hits" : [
                {
                  "_index" : "logs-2019.07.01",
                  "_type" : "_doc",
                  "_id" : "x-FB2GsBn6OwEwpDhYjX",
                  "_score" : 1.0,
                  "_source" : {
                    "log" : "0701125212",
                    "name" : "5018",
                    "date" : "2019/07/01 12:44:58:595"
                  }
                }
              ]
            }
          }
        },
        {
          "key" : "0701143900",
          "doc_count" : 3,
          "docs" : {
            ...
          }
        }
  ...
}

在基巴纳州...

具有与上述索引/数据相同的假设:

  1. 使用左侧导航栏转到Visualize构建器
  2. 创建新的数据表可视化,然后选择包含日志的索引模式
  3. 选择Top Hits作为指标(显示并排序所需的任何字段),并选择Terms聚合以按doc字段存储行 Kibana - Metrics and Buckets config
  4. 运行可视化工具应创建一个两列的表,其中一列具有唯一条件,另一列中具有选定的热门歌曲Field

就是这样!现在,根据定义的唯一性标准,您应该有一张表,每条“唯一”记录有一行。

选项

多字段唯一性

如果您要在唯一性条件中使用多个字段,而又不更改映射/索引,则唯一的选择就是在术语汇总中使用script而不是"field": "doc" 。在Elasticsearch查询中,这很简单:

POST /logs/_search
{
  "size": 0,
  "aggs": {
    "unique_logs": {
      "terms": {
        // Remove the "field" from the agg...
        // "field": "log",
        // ...and add a "script" instead.
        "script": {
          "source": "String.format('%s.%s', new def[]{doc['log'].value, doc['name'].value})",
          "lang": "painless"
        },
        "size": 10
      },
      ...
    }
  }
}

在Kibana中,您执行相同的操作,只需单击几下即可到达那里:

  1. 添加新的scripted field,以连接所需的“唯一性”字段(使用上面直接来自ES示例的脚本作为模板)。
  2. 在可视化的Buckets配置中,从Field下拉列表中选择新创建的脚本字段。

在Kibana中每行显示多个字段

尽管热门匹配汇总支持返回整个匹配,但不幸的是,Kibana数据表可视化仅支持每行显示一个字段。如果要每行显示更多数据,则必须创建一个scripted field,其中包含要显示的数据。

类似于多字段唯一键示例,您可以编写一个脚本来格式化带有某些字段组合的某些字符串:

String.format('[%s] %s - %s', new def[]{doc['log'].value, doc['date'].value, doc['name'].value})

注意事项

  1. 您的解决方案对脚本的依赖程度越高,就越有可能变得无效。尝试尽可能地限制脚本(即-如果可以,请仅使用一个字段以确保唯一性)
  2. 对于可视化,您可能希望创建“保存的搜索”而不是直接在索引模式上创建它来限制正在搜索和可视化的文档数量,因为这种聚合可能会昂贵,因为它正在运行脚本。