背景介紹
我們在 Elasticsearch
API的基礎上實現了一個日誌查詢系統,支持最基本的時間範圍選擇以及關鍵詞搜索高亮,並且日誌展示的表格支持異步分頁。
有天用戶反饋,查詢的時候頁面報錯
Result window is too large, from + size must be less than or equal to: [10000] but was [24600]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.
這是因爲我們的異步分頁查詢邏輯中使用了 from
+ size
,而 Elasticsearch
默認配置爲
“max_result_window”: “10000”
於是, 將這個參數調至 30000, 問題暫時解決。
不過,今天又接到反饋,API報錯
Result window is too large, from + size must be less than or equal to: [30000] but was [44600]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.
一味調整 max_result_window
不是個辦法,遂計劃詳細瞭解下 window
查詢的邏輯,以及 max_result_window
這個參數存在的意義。
Elasticsearch Search 搜索
我們的查詢DSL大致如下:
{
"from": m,
"size": n,
"sort": [{"l": "asc"}, {"line": "asc"}],
"query": {}
}
ES的 Search 搜索是分兩個階段進行的,即Query和Fetch階段。
Query 階段
- 每個
Shard
通過查詢倒排索引,獲取滿足查詢結果的有序文檔ID優先隊列,隊列長度爲 from + size - 每個
Shard
返回有序文檔列表發送給協調節點,協調節點把所有Shard
的結果合併產生一個全局排序後的優先隊列,隊列長度爲 from + size
Fetch 階段
- 根據 Query 階段返回的結果隊列決定哪些文檔需要被取回,在長度爲 from + size 的隊列中,前from個文檔會被丟棄,只有最後size個文檔需要被取回,而這些文檔可能來自於一個或者多個分片
- 協調節點給相關文檔的分片創建一個
Multi Get
請求,一旦所有文檔被取回,協調節點返回結果給客戶端。
max_result_window 參數的意義
在 Query 階段中,協調節點需要在長度爲 number_of_shard * (from + size)
的排序文檔中,找到包含在 size
中的文檔。
這個性能,取決於文檔大小/分片個數以及硬件性能等,當 from
值足夠大時,這個過程會變得沉重,消耗大量的資源,這也是 Elasticsearch
不推薦使用深度分頁以及 max_result_window
存在的意義。
Elasticsearch Scroll 搜索
在瞭解深度分頁的過程中,看見推薦使用 Scroll
完成深度分頁,於是同時瞭解了一下 Scroll
查詢
Scrolling is not intended for real time user requests, but rather for processing large amounts of data, e.g. in order to reindex the contents of one index into a new index with a different configuration.
首先,Scroll
並不適合用來做實時搜索,更適用於大規模數據處理,例如 reindex
Scroll
的使用也分爲兩個階段,初始化和遍歷。
初始化時將所有符合搜索條件的搜索結果文檔ID緩存起來, 形成快照,遍歷時直接從快照取數據。
初始化會返回一個 scroll_id
,每次遍歷時都帶上這個id,重複遍歷知道返回的數據爲空,刪除快照。
總結:
與 Search
相比將Query階段的隊列緩存起來,多次查詢時減少 Query階段的操作,以提高性能?(待繼續驗證)