1. 程式人生 > >Elasticsearch Terms聚合效能提升10倍

Elasticsearch Terms聚合效能提升10倍

{
  "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