本篇文章將會講解ES兩種分頁查詢方法以及優缺點
注意:以下文章中的命令和java代碼均基於ES5.3.0版本
一、from/size分頁
官網文檔地址:https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-request-from-size.html
查詢的時候帶上from和size兩個參數即可
- from參數默認爲0,size參數默認爲10
- 查詢結果索引 from + size 的值不能超出index.max_result_window,默認該值是10000
- 如果想做深度分頁,可以考慮使用 Scroll 或者Search After 方式。
1.修改默認窗口大小
PUT請求 `{{es-host}}/索引名字/_settings
{
"index": {
"max_result_window": 1000000
}
}
可以適當增大窗口值大小方便常用分頁查詢
2.JAVA API
transportClient.prepareSearch(索引名)
.setQuery(mixQuery)
.setFrom((pageNum - 1) * pageSize)
.setSize(pageSize)
.setFetchSource(true);
3.優缺點
優點就是簡單,和mysql的分頁很相似
缺點也很明顯,首先,分頁受限於結果窗口大小,而該值默認值僅僅是10000,就算可以調整該分頁大小,仍然讓人心裏不爽快,再者,隨着分頁from的值越來越大,效率會越來越低。from/size的分頁原理是先查詢出所有結果,然後根據from和size進行結果截取,所以勢必會隨着分頁深度的增加效率越來越低。最後,由於需要將查詢結果都加載到內存,有可能會出現內存爆掉的情況發生。
二、Scroll分頁
從from/size的官網爲文檔上來看,如果需要“深分頁”,最好使用Scroll or Search After API。
官網文檔:https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-request-scroll.html
scroll效率之所以高,是因爲它內部維護着一個“遊標”,類似於指針的東西,每次查詢完size個數據,遊標就會移動到查詢數據的尾部等待下次查詢。
1.初次請求
請求方式
POST
請求地址
{{es-host}}/website/_search?scroll=1m
請求體
{
"size": 1,
"query": {
"match_all": {}
}
}
響應結果
{
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAANLb6Flg4V2VGRndwUW91SnBVWUlxcTJzc2cAAAAAADS2-RZYOFdlRkZ3cFFvdUpwVVlJcXEyc3NnAAAAAAA0tvgWWDhXZUZGd3BRb3VKcFVZSXFxMnNzZwAAAAAANLb8Flg4V2VGRndwUW91SnBVWUlxcTJzc2cAAAAAADS2-xZYOFdlRkZ3cFFvdUpwVVlJcXEyc3Nn",
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 1.0,
"hits": [
{
"_index": "website",
"_type": "blog",
"_id": "AXoGPweiCycsj4NKux3V",
"_score": 1.0,
"_source": {
"name": "test"
}
}
]
}
}
初次請求和正常的請求沒什麼區別,就加上一個參數scroll=1m
即可,表示本次scroll遊標一分鐘內有效。
接着,拿到的結果中除了正常返回的數據,還多了一個_scroll_id
參數,下次請求就可以直接使用該參數進行分頁查詢了。
2.以後的請求
請求方式
GET
請求地址
{{es-host}}/_search/scroll?scroll=1m&scroll_id=DnF1ZXJ5VGhlbkZldGNoBQAAAAAANL04FmJrRjY5VkpFUm0yMjZvc2s5VF91S0EAAAAAADS9NhZia0Y2OVZKRVJtMjI2b3NrOVRfdUtBAAAAAAA0vTcWYmtGNjlWSkVSbTIyNm9zazlUX3VLQQAAAAAANL05FmJrRjY5VkpFUm0yMjZvc2s5VF91S0EAAAAAADS9OhZia0Y2OVZKRVJtMjI2b3NrOVRfdUtB
請求體
無
響應結果
{
"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAANL04FmJrRjY5VkpFUm0yMjZvc2s5VF91S0EAAAAAADS9NhZia0Y2OVZKRVJtMjI2b3NrOVRfdUtBAAAAAAA0vTcWYmtGNjlWSkVSbTIyNm9zazlUX3VLQQAAAAAANL05FmJrRjY5VkpFUm0yMjZvc2s5VF91S0EAAAAAADS9OhZia0Y2OVZKRVJtMjI2b3NrOVRfdUtB",
"took": 1,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 1.0,
"hits": [
{
"_index": "website",
"_type": "blog",
"_id": "AXlizj8kCycsj4NKuvL8",
"_score": 1.0,
"_source": {
"name": "cve-2015-1427"
}
}
]
}
}
可以看到,再次請求的時候不需要再指定索引名稱和相關的複雜查詢條件,直接告訴ES上一次查詢的遊標_scroll_id即可。
3.JAVA API
SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(index.split(","))
.setQuery(mixQuery)
.setSize(pageSize)
.setFetchSource(true)
.setScroll(TimeValue.timeValueMinutes(1))
.addSort(fieldSortBuilder);
只需要加上 .setFetchSource(true)即可。
第一次查詢之後要正常處理結果數據,並非像是某些文章中講的只是返回scroll_id
之後的查詢則就簡單多了
scrollId = searchResponse.getScrollId();
while (searchResponse.getHits().getHits().length > 0) {
//處理結果數據
SearchScrollRequestBuilder searchScrollRequestBuilder = transportClient.prepareSearchScroll(scrollId).setScroll(TimeValue.timeValueMinutes(1));
searchResponse = searchScrollRequestBuilder.execute().actionGet();
scrollId = searchResponse.getScrollId();
}
三、Search After分頁
文檔地址:https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-request-search-after.html
沒用過,略。