ES 為了避免深分頁,不允許使用分頁(from & size)查詢 10000 條以後的數據,因此如果要查詢第 10000 條以後的數據,要使用 ES 提供的 scroll 游標 來查詢
index.max_result_window:10000
作爲保護措施 ,即默認 from + size 不能超過 10000,雖然這個參數可以動態修改,也可以在配置文件配置,但是最好不要這麼做,應該改用 ES 提供的 scroll 方法來取得數據scroll 游標原理
具體實例
初始化
請求
注意要在URL中的search後加上 scroll=1m
,不能寫在 request body 中,其中 1m
表示這個游標要保持開啟 1 分鐘
可以指定 size 大小,就是每次回傳幾筆數據,當回傳到沒有數據時,仍會返回 200 成功,只是 hits 裡的 hits 會是空 list
在初始化時除了回傳 _scroll_id
,也會回傳前 100 筆(假設 size = 100)的數據
request body 和一般搜索一樣,因此可以說在初始化的過程中,除了加上 scroll 設置游標開啟時間之外,其他的都跟一般的搜尋沒有兩樣(要設置查詢條件,也會回傳前 size 筆的數據)
GET my_index/_search?scroll=1m
{
"query":{
"range":{
"createTime": {
"gte": 1522229999999
}
}
},
"size": 1000
}
返回結果
{
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAfv5-FjNOamF0Mk1aUUhpUnU5ZWNMaHJocWcAAAAAAH7-gBYzTmphdDJNWlFIaVJ1OWVjTGhyaHFnAAAAAAB-_n8WM05qYXQyTVpRSGlSdTllY0xocmhxZwAAAAAAdsJxFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbCcBZlZGUwSWpSVlJqeVJiN1dBWHNpUG1R",
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 84,
"max_score": 1,
"hits": [
{
"_index": "video1522821719",
"_type": "doc",
"_id": "84056",
"_score": 1,
"_source": {
"title": "三个院子",
"createTime": 1522239744000
}
}
....99 data
]
}
}
遍歷數據
請求
使用初始化返回的 _scroll_id
來進行請求,每一次請求都會繼續返回初始化中未讀完數據,並且會返回一個 _scroll_id
,這個 _scroll_id
可能會改變,因此每一次請求應該帶上上一次請求返回的 _scroll_id
要注意返回的是 _scroll_id
,但是放在請求裡的是 scroll_id
,兩者拼寫上有不同
且每次發送 scroll 請求時,都要再重新刷新這個 scroll 的開啟時間,以防不小心超時導致數據取得不完整
GET _search/scroll?scroll=1m
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB"
}
返回結果
如果沒有數據了,就會回傳空的 hits,可以用這個判斷是否遍歷完成了數據
{
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB",
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 84,
"max_score": null,
"hits": []
}
}
優化scroll查詢
在一般場景下,scroll 通常用來取得需要排序過後的大筆數據,但是有時候數據之間的排序性對我們而言是沒有關係的,只要所有數據都能取出來就好,這時能夠對 scroll 進行優化
初始化
使用 _doc
去 sort 得出來的結果,這個執行的效率最快,但是數據就不會有排序,適合用在只想取得所有數據的場景
GET my_index/_search?scroll=1m
{
"query": {
"match_all" : {}
},
"sort": ["_doc"]
}
清除 scroll
雖然我們在設置開啟 scroll 時,設置了一個 scroll 的存活時間,但是如果能夠在使用完順手關閉,可以提早釋放資源,降低 ES 的負擔
DELETE _search/scroll
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB"
}