Elasticsearch Terms聚合性能提升10倍

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangmaohong0717/article/details/82429278
{
  "size": 0,
  "query": {
    "bool": {
      "filter": {
        "range": {
          "requestTime": {
            "from": 1536127200000,
            "to": 1536135000006,
            "include_lower": true,
            "include_upper": true
          }
        }
      }
    }
  },
  "aggregations": {
    "ip": {
      "terms": {
        "field": "ip",
        "size": 50
      },
      "aggregations": {
        "modeZero": {
          "filter": {
            "term": {
              "mode": "0"
            }
          },
          "aggregations": {
            "userName": {
              "cardinality": {
                "field": "userName"
              }
            }
          }
        },
        "resultOne": {
          "filter": {
            "term": {
              "result": "1"
            }
          },
          "aggregations": {
            "userName": {
              "cardinality": {
                "field": "userName"
              }
            }
          }
        }
      }
    }
  }
}
  • 结果:
    "took": 3435,
    "timed_out": false,
    "_shards": {
    
        "total": 25,
        "successful": 25,
        "failed": 0
    
    },
    "hits": {
    
        "total": 715625,
        "max_score": 0,
        "hits": [ ]
    
    }

    速度很慢,修改下语句,terms aggregation内部加一个 "execution_hint": "map"。

  • 结果:

    {
    
        "took": 265,
        "timed_out": false,
        "_shards": {
            "total": 25,
            "successful": 25,
            "failed": 0
        },
        "hits": {
            "total": 715625,
            "max_score": 0,
            "hits": [ ]
        }

    性能提升了10倍以上。原因如下:

  • Terms aggregation默认的计算方式并非直观感觉上的先查询,然后在查询结果上直接做聚合。

    ES假定用户需要聚合的数据集是海量的,如果将查询结果全部读取回来放到内存里计算,内存消耗会非常大。因此ES利用了一种叫做global ordinals的数据结构来对聚合的字段来做bucket分配,这个ordinals用有序的数值来代表字段里唯一的一个字符串,因此为每个ordinals值分配一个bucket就等同于为每个唯一的term分配了bucket。 之后遍历查询结果的时候,可以将结果映射到各个bucket里,就可以很快的统计出每个bucket里的文档数了。

    这种计算方式主要开销在构建global ordinals和分配bucket上,如果索引包含的原始文档非常多,查询结果包含的文档也很多,那么默认的这种计算方式是内存消耗最小,速度最快的。

    如果指定execution_hint:map则会更改聚合执行的方式,这种方式不需要构造global ordinals,而是直接将查询结果拿回来在内存里构造一个map来计算,因此在查询结果集很小的情况下会显著的比global ordinals快。 

    要注意的是这中间有一个平衡点,当结果集大到一定程度的时候,map的内存开销带来的代价可能就抵消了构造global ordinals的开销,从而比global ordinals更慢,所以需要根据实际情况测试对比一下才能找好平衡点。
     

  • 地址:https://elasticsearch.cn/question/1008

  • terms聚合详解官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/2.4/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-execution-hint

  • terms聚合测试结果可以看:https://blog.csdn.net/laoyang360/article/details/79253294

猜你喜欢

转载自blog.csdn.net/wangmaohong0717/article/details/82429278