深度分頁問題大致可以分爲兩類
- 隨機深度分頁:隨機跳轉頁面
- 滾動深度分頁:只能一頁一頁往下查詢
本文得search After 處理的是滾動深度分頁的問題
在舊版本中,ES爲深度分頁有scroll search 的方式,官方的建議並不是用於實時的請求,因爲每一個 scroll_id 不僅會佔用大量的資源(特別是排序的請求),而且是生成的歷史快照,對於數據的變更不會反映到快照上。這種方式往往用於非實時處理大量數據的情況,比如要進行數據遷移或者索引變更之類的。那麼在實時情況下如果處理深度分頁的問題呢?es 給出了 search_after 的方式,這是在 >= 5.0 版本才提供的功能。
這也是本文要重要講解的內容
基本思想:searchAfter的方式通過維護一個實時遊標來避免scroll的缺點,它可以用於實時請求和高併發場景。
🤔思考:那search After 爲什麼不用產生臨時快照之類的存儲信息,就能保證滾動順序讀取數據呢?
每個文檔具有一個唯一值的字段應該用作排序規範的仲裁器。否則,具有相同排序值的文檔的排序順序將是未定義的。建議的方法是使用字段_id,它肯定包含每個文檔的一個唯一值。
POST twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "es"
}
},
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
返回出的結果信息
{
"took" : 29,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
...
},
"sort" : [
...
]
},
{
...
},
"sort" : [
124648691,
"624812"
]
}
]
}
}
上面的請求會爲每一個文檔返回一個包含sort排序值的數組。這些sort排序值可以被用於 search_after 參數裏以便抓取下一頁的數據。比如,我們可以使用最後的一個文檔的sort排序值,將它傳遞給 search_after 參數:
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "es"
}
},
"search_after": [124648691, "624812"],
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
注意:當我們使用search_after時,from值必須設置爲0或者-1。
search_after缺點是不能夠隨機跳轉分頁,只能是一頁一頁的向後翻,並且需要至少指定一個唯一不重複字段來排序。它與滾動API非常相似,但與它不同,search_after參數是無狀態的,它始終針對最新版本的搜索器進行解析。因此,排序順序可能會在步行期間發生變化,具體取決於索引的更新和刪除。