Elasticsearch調研深度查詢
1.from/size 淺分頁查詢
一般的分頁需求我們可以使用from和size的方式實現,但是這種的分頁方式在深分頁的場景下應該是避免使用的。深分頁的頁次增加,所消耗的記憶體和時間的增長也是成比例的增加,為了避免深度分頁產生的問題,Elasticsearch從2.0版本楷書,增加了一個限制:
index.max_result_window = 10000
# elasticsearch的一種保護機制,限制1w條資料,但是可以修改最大限根據實際需求,不過最好不要修改會影響效能。
# 引入scroll
from/size查詢查詢在10000-50000條資料(1000到5000頁)以內的時候還是可以的,但是如何資料量過多的話,就會出現深分頁的問題
# 為了解決以上問題,elasticsearch提出了一個scroll捲動的方式。
1.scroll的原理是講索引資料備份,每次記住最後一次查詢的位置,下一次從最後一次位置開始查詢。
2.使用scroll,通過size的查詢最大限制,scroll返回一個代表最後一個size查詢的位置scroll_id可以不斷的獲取下一頁的內容。
GET dlp-prd-rabbitmq-tagfile-*/_search?scroll=10m
{
"query": {
"match_all": {}
},
"sort": [{"stime": {"order": "desc"}}],
"from": 0,
"size": 10000
}
1.scroll=5m表示設定scroll_id保留5分鐘可用。
2.使用scroll必須要將from設定為0。
3.size決定後面每次呼叫_search搜尋返回的數量
1.然後我們可以通過資料返回的_scroll_id讀取下一頁內容,每次請求將會讀取下10000條資料,直到資料讀取完畢或者scroll_id保留時間截止
2.請求的介面不再使用索引名了,而是 _search/scroll,其中GET和POST方法都可以使用。
GET /_search/scroll
{
"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAC7EWa1U5THR6U0xSSXVOZjJTaUhpeHY2dw==",
"scroll": "10m"
}
1.根據官方檔案的說法,scroll的搜尋上下文會在scroll的保留時間截止後自動清除,但是我們知道scroll是非常消耗資源的,所以一個建議就是當不需要了scroll資料的時候,儘可能快的把scroll_id顯式刪除掉,而且會生成歷史快照,對於資料的變更不會反映到快照上。
DELETE /_search/scroll/DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAC7EWa1U5THR6U0xSSXVOZjJTaUhpeHY2dw==
1.可以看出scroll不適合支援那種實時的和使用者互動的前端分頁工作,其主要用途用於從ES叢集分批拉取大量結果集的情況,一般都是offline的應用場景。 比如需要將非常大的結果集拉取出來,存放到其他系統處理,或者需要做大索引的reindex等等。
3.深分頁search_after
建議使用Scroll api進行高效深度捲動,但捲動上下文代價很高,建議不要將其用於實時使用者請求。該search_after引數通過提供實時遊標來解決此問題。
search_after使用
1.search_after是ES5.0及之後版本提供的新特性,search_after有點類似scroll,但是和scroll又不一樣,它提供一個活動的遊標,通過上次查詢的最後一條資料來進行下一次查詢。
2.search_after分頁的方式是根據上一頁的最後一條資料來確定下一頁的位置,同時在分頁請求的過程中,如果有索引資料的增刪改查,這些變更也會實時的反映到遊標上。
3.但是需要注意,因為每一頁的資料都是依賴於上一頁最後一條資料,所以無法跳頁請求。
1.search after 不能指定頁數,只能一頁挨一頁問下查。第一次查詢時帶上sort,返回最後一個檔案的id欄位
1.每個檔案具有一個唯一值的欄位應該用作排序規範的仲裁器。否則,具有相同排序值的檔案的排序順序將是未定義的。建議的方法是使用欄位_id,它肯定包含每個檔案的一個唯一值。
2.為了找到每一頁最後一條資料,每個檔案必須有一個全域性唯一值,官方推薦使用 _uid 作為全域性唯一值,其實使用業務層的 id 也可以。
GET dlp-prd-rabbitmq-tagfile-*/_search
{
"query": {
"match_all": {}
},
"sort": [
{"stime": {"order": "desc"}},
{"_id": {"order": "desc"}}
],
"from": 0,
"size": 10000
}
# 為了根據最後一條資料的唯一標識來查詢1w後面的資料
1.可以使用id的唯一標識,或者id加stime時間,來查詢1w的後面資料。
2.當前我們search_after使用的唯一標識有id和stime,那麼sort排序就必須加入stime和id排序不然會報錯。
2.下一次查詢帶上search after引數
1.上面的請求會為每一個檔案返回一個包含sort排序值的陣列。這些sort排序值可以被用於 search_after 引數裡以便抓取下一頁的資料。比如,我們可以使用最後的一個檔案的sort排序值,將它傳遞給 search_after 引數:
GET dlp-prd-rabbitmq-tagfile-*/_search
{
"query": {
"match_all": {}
},
"sort": [
{"stime": {"order": "desc"}},
{"_id": {"order": "desc"}}
],
"search_after": ["2022-09-25T12:38:42.142Z", "pxOodIMBf53JeIypLfhE"],
"from": 0,
"size": 10000
}
使用search_after必須要設定from=0。
這裡我使用timestamp和_id作為唯一值排序。
我們在返回的最後一條資料裡拿到sort屬性的值傳入到search_after。
3.刪除和特性
1.search_after不是自由跳轉到隨機頁面而是並行捲動多個查詢的解決方案。它與捲動API非常相似,但與它不同,search_after引數是無狀態的,它始終針對最新版本的搜尋器進行解析。因此,排序順序可能會在步行期間發生變化,具體取決於索引的更新和刪除。
4.search_after應用場景
1.不支援跳頁查詢
# 另外在ES6.5的檔案中有這樣一句話需要注意一下:
2.另外,search_after並不是隨機的查詢某一頁資料,而是並行的滾屏查詢;search_after的查詢順序會在更新和刪除時發生變化,也就是說支援實時的資料查詢
3.大致的意思就是,如果search_after中的關鍵字為654,那麼654323的檔案也會被搜尋到,所以在選擇search_after的排序欄位時需要謹慎,可以使用比如檔案的id或者時間戳等