1. 程式人生 > >es實戰之查詢大量數據

es實戰之查詢大量數據

刪除 walk parameter 好用 param eap 數據導出 安裝 多個

背景

項目中已提供海量日誌數據的多維實時查詢,客戶提出新需求:將數據導出。

將數據導出分兩步:

  1. 查詢大量數據
  2. 將數據生成文件並下載

本文主要探討第一步,在es中查詢大量數據或者說查詢大數據集。

es支持的查詢數量

es默認支持的查詢數量或者說查詢深度是10,000。

可以動態修改max_result_window這個參數的設置,默認為10,000。

PUT xz-logs/_settings?preserve_existing=true
{
  "index.max_result_window" : "10000000"
}

es search api

from + size

GET /_search
{
    "from" : 0, "size" : 10,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

當Elasticsearch響應請求時,它必須確定docs的順序,全局排序響應結果。
如果請求的頁數較少時,假設每頁10個docs——即pageSize=10, 此時Elasticsearch不會有什麽問題。

但若取的頁數較大時(深分頁),如請求第20頁,Elasticsearch不得不取出所有分片上的第1頁到第20頁的所有docs,假設你有16個分片,則需要在coordinate node 匯總到 shards* (from+size)條記錄,即需要 16*(20+10)記錄後做一次全局排序,再最終取出 from後的size條結果作為最終的響應。

所以:當索引非常非常大(千萬或億),是無法安裝 from + size 做深分頁的,分頁越深則越容易OOM,即便不OOM,也是很消耗CPU和內存資源的。

scroll

scroll類似於數據庫中的遊標。

遊標查詢允許我們 先做查詢初始化,然後再批量地拉取結果。 這有點兒像傳統數據庫中的 cursor 。

遊標查詢會取某個時間點的快照數據。 查詢初始化之後索引上的任何變化會被它忽略。 它通過保存舊的數據文件來實現這個特性,結果就像保留初始化時的索引 視圖 一樣。

深度分頁的代價根源是結果集全局排序,如果去掉全局排序的特性的話查詢結果的成本就會很低。 遊標查詢用字段 _doc 來排序。 這個指令讓 Elasticsearch 僅僅從還有結果的分片返回下一批結果。

第一次查詢

GET /old_index/_search?scroll=1m 
{
    "query": { "match_all": {}},
    "sort" : ["_doc"], 
    "size":  1000
}

第二次查詢

GET /_search/scroll
{
    "scroll": "1m", 
    "scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs="
}

Scanning Scroll API

如果只對查詢結果感興趣而不關心結果的順序,可以使用更高效的scanning scroll。使用方法非常簡單,只需在查詢語句後加上“search_type=scan”即可。

search after(5.0新特性)

search_after is not a solution to jump freely to a random page but rather to scroll many queries in parallel. It is very similar to the scroll API but unlike it, the search_after parameter is stateless, it is always resolved against the latest version of the searcher. For this reason the sort order may change during a walk depending on the updates and deletes of your index.

search_after類似於scroll,不同之處是:search_after是無狀態的,它總是針對最新版本的搜索器進行解析。由於更新或者刪除索引,搜索的排序結果可能會發生變化。

bulk

bulk是將多個請求合並成一個請求,如下所示:

POST _bulk
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

其他

插件: elasticsearch-dataformat

實際使用過程中,該插件不好用。如果帶查詢條件,數據無法導出。查看其依賴的jar包,估計其調用poi來生成csv文件, 估計速度快不了。

這種插件做demo可以,實際生成中,不太敢使用,因為不可控因素太多。

總結

綜上所述,最後采用scroll api來解決es查詢大量數據的問題。不過數據量大一點,查詢時間就比較長,在本人的集群中,查詢10w條,需要將近1分鐘的時間。(附本人集群:3個節點。每個節點配置為cpu 8核,heap size 16G,每個索引有5個分片、1個副本。數據量每天4500w)

es實戰之查詢大量數據