profiler

profiler 是 Elasticsearch 5.0 的一个新接口。通过这个功能,可以看到一个搜索聚合请求,是如何拆分成底层的 Lucene 请求,并且显示每部分的耗时情况。

启用 profiler 的方式很简单,直接在请求里加一行即可:

  1. curl -XPOST 'http://localhost:9200/_search' -d '{
  2. "profile": true,
  3. "query": { ... },
  4. "aggs": { ... }
  5. }'

可以看到其中对 query 和 aggs 部分的返回是不太一样的。

query

query 部分包括 collectors、rewrite 和 query 部分。对复杂 query,profiler 会拆分 query 成多个基础的 TermQuery,然后每个 TermQuery 再显示各自的分阶段耗时如下:

  1. "breakdown": {
  2. "score": 51306,
  3. "score_count": 4,
  4. "build_scorer": 2935582,
  5. "build_scorer_count": 1,
  6. "match": 0,
  7. "match_count": 0,
  8. "create_weight": 919297,
  9. "create_weight_count": 1,
  10. "next_doc": 53876,
  11. "next_doc_count": 5,
  12. "advance": 0,
  13. "advance_count": 0
  14. }

aggs

  1. "time": "1124.864392ms",
  2. "breakdown": {
  3. "reduce": 0,
  4. "reduce_count": 0,
  5. "build_aggregation": 1394,
  6. "build_aggregation_count": 150,
  7. "initialise": 2883,
  8. "initialize_count": 150,
  9. "collect": 1124860115,
  10. "collect_count": 900
  11. }

我们可以很明显的看到聚合统计在初始化阶段、收集阶段、构建阶段、汇总阶段分别花了多少时间,遍历了多少数据。

注意其中 reduce 阶段还没实现完毕,所有都是 0。因为目前 profiler 只能在 shard 级别上做统计。

collect 阶段的耗时,有助于我们调整对应 aggs 的 collect_mode 参数选择。目前 Elasticsearch 支持 breadth_firstdepth_first 两种方式。

initialise 阶段的耗时,有助于我们调整对应 aggs 的 execution_hint 参数选择。目前 Elasticsearch 支持 mapglobal_ordinals_low_cardinalityglobal_ordinalsglobal_ordinals_hash 四种选择。在计算离散度比较大的字段统计值时,适当调整该参数,有益于节省内存和提高计算速度。

对高离散度字段值统计性能很关注的读者,可以关注 https://github.com/elastic/elasticsearch/pull/21626 这条记录的进展。