如何在Elasticsearch中聚合结果?

时间:2019-12-16 19:27:54

标签: elasticsearch elasticsearch-aggregation

我想使用Elasticsearch聚合其他聚合的结果。我创建了我需要的第一个聚合:

es.search(index='stackoverflow', body = {
    "size":0,
    "query": {
        "bool": {
          "filter": {
              "match" : {"type": "Posts"}
          },
          "filter": {
              "match" : {"PostTypeId": "1"}
          }
        }
    },
    "aggs" : {
        "by_user": {
          "terms": {
            "field": "OwnerUserId"
          }
        }
    }
})

此查询获取所有属于问题( PostTypeId = 1 )的 post 类型的文档。然后,它通过 OwnerUserId 进行汇总,该计数计算每个用户的问题帖子数,得出以下结果:

{'took': 0,
 'timed_out': False,
 '_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0},
 'hits': {'total': {'value': 10000, 'relation': 'gte'},
  'max_score': None,
  'hits': []},
 'aggregations': {'by_user': {'doc_count_error_upper_bound': 0,
   'sum_other_doc_count': 31053,
   'buckets': [{'key': '2230', 'doc_count': 223},
    {'key': '', 'doc_count': 177},
    {'key': '38304', 'doc_count': 158},
    {'key': '5997', 'doc_count': 144},
    {'key': '4048', 'doc_count': 130},
    {'key': '25813', 'doc_count': 119},
    {'key': '27826', 'doc_count': 119},
    {'key': '2633', 'doc_count': 115},
    {'key': '19919', 'doc_count': 114},
    {'key': '13938', 'doc_count': 111}]}}}

现在,我想对上一个结果进行另一个汇总:按 doc_count 汇总,我的意思是对相等数量的问题帖子进行分组和计数。对于先前的结果,我想要的结果将是:

{'buckets': [{'key': '223', 'doc_count': 1},
    {'key': '177', 'doc_count': 1},
    {'key': '158', 'doc_count': 1},
    {'key': '144', 'doc_count': 1},
    {'key': '130', 'doc_count': 1},
    {'key': '119', 'doc_count': 2},
    {'key': '115', 'doc_count': 1},
    {'key': '114', 'doc_count': 1},
    {'key': '111', 'doc_count': 1}]}

2 个答案:

答案 0 :(得分:0)

您可以尝试使用Bucket sort aggregation,这对排序其他aggs的结果很有用。

在此Elasticsearch forum中,用户共享了其他方式来对术语汇总进行排序。对于您的情况,您将使用“ doc_count”(或“ count”,我现在不记得了)字段以升序对结果进行排序。

请记住,嵌套聚合会降低群集的性能。也就是说,要花费更多的时间才能得到结果。

希望这会有所帮助! :)

答案 1 :(得分:0)

我可以找到一种方法(至少直接)聚合结果。正如我在Elasticsearch论坛上所读到的那样,这种用例不是可以考虑的,因为它效率很低。

为了解决用例,我要做的是利用transform API将第一个聚合存储在时间索引中,然后对那个索引执行第二个聚合。

首先,我创建一个转换以执行第一次聚合(按OwnerUserId分组并计算每个用户发布的问题数):

url = 'http://localhost:9200/_transform/transform_rq1'
headers = {
   'Content-Type': 'application/json'
}
query = {
  "source": {
    "index": "posts",
    "query": {
        "bool": {
          "filter": {
              "match" : {"PostTypeId": "1"}
          }
        }
    }
  },
  "dest": {
    "index": "rq1"
  },
  "pivot": {
    "group_by": {
      "OwnerUserId": {
        "terms": {
          "field": "OwnerUserId"
        }
      }
    },
    "aggregations": {
      "count": {
        "value_count": {
          "field": "OwnerUserId"
        }
      }
    }
  }
}

response = requests.put(url, headers=headers, data=json.dumps(query))

然后,我开始执行转换以执行它:

url = 'http://localhost:9200/_transform/transform_rq1/_start'
headers = {
   'Content-Type': 'application/json'
}

response = requests.post(url, headers=headers).json()

最后,我在创建的时间索引上执行第二次汇总(按每个用户的问题数量分组,以获取多少用户发布了多少个问题):

response = es.search(index='rq1', body = {
    "size":0,
    "query": {
                "match_all": {}
             },
    "aggs" : {
        "by_num": {
          "terms": {
            "field": "count",
            "order" : { "_key" : "asc" },
            "size": 30000
          }
        }
    }
})

print(response)

如您所见,我已经用Python编写了这段代码。