Elasticsearch - 唯一计数的聚合

时间:2016-04-27 03:12:55

标签: elasticsearch subquery aggregation

我有一个Elasticsearch书籍数据库:

{
  "id": 1,
  "name": "Animal Farm"
},
{
  "id": 2,
  "name": "Brave New World"
},
{
  "id": 3,
  "name": "Nineteen Eighty-Four"
},
{
  "id": 4,
  "name": "Animal Farm"
},
{
  "id": 5,
  "name": "We"
}

如您所见,id 14的图书的冲突书名为“动物农场”。但是,它们是不同的书籍。一个是George Orwell,另一个是农场动物。

我想知道书名经常发生冲突的频率。对于上面的示例,预期结果为:

{
  "conflicts": [
    {
      "num_of_books": 2,
      "count": "1"
    },
    {
      "num_of_books": 1,
      "count": "3"
    }
  ]
}

num_of_books 2的条目是“动物农场”的冲突,它发生一次(因此count1)。其他3本书的名称各有不同,因此它们会显示在num_of_books 1count 3的条目中。我需要书籍的名称。只有重要的事情。

我知道SQL有“子查询”来执行此操作:

SELECT num_of_books, COUNT(*) AS _count
FROM (
  SELECT COUNT(*) AS num_of_books
  FROM books
  GROUP BY name
)
GROUP BY num_of_books;

我阅读了Nested AggregationSub-Aggregations的文章,但没有看到实现目标的可能性。

任何评论都会有所帮助,谢谢!

1 个答案:

答案 0 :(得分:0)

据我所知,ES中尚无法在聚合上运行聚合。我知道一些关于允许在存储桶聚合结果上应用额外逻辑的未决问题,但它们仍在讨论和争论中。

在您的情况下,您可以使用terms聚合来逃避内部SQL查询,以便使用min_doc_count: 2获取所有冲突书籍的名称。

{
    "size": 0,
    "aggs": {
        "books": {
            "terms": {
                "field": "name",
                "min_doc_count": 2
            }
        }
    }
}

然后,您可以解析客户端上的存储桶,并根据其计数将它们重新装入新的num_of_books存储桶。例如,使用head插件,您可以在Transform部分

中添加以下代码
var num_of_books = {};
root.aggregations.books.buckets.forEach(function(b) {
    num_of_books[b.doc_count] = (num_of_books[b.doc_count] || 0) + 1;
});
return num_of_books;

num_of_books将包含以下内容:

{
    "2": 1,
    "1": 3
}