Elasticsearch的數據都存在每個節點的分片中,當執行搜索時每個分片獨立搜索后,數據再經過整合返回。ElasticSearch的搜索請求一次請求最大量為10000。如果超過則會發生錯誤。那么,如果數據量很大,就必須實現分頁查詢。Elasticsearch中分頁方式大致有兩種:from-size分頁以及Scroll分頁
from-size分頁
from-size分頁可以理解為簡單意義上的分頁。它的原理很簡單,就是查詢前200條數據,然后截斷前100條,只返回100-200的數據。這樣如果每頁的數據很多的話會存在很大的資源浪費。
查詢方式如下:
SearchResponse response = client.prepareSearch("test_index")
.setTypes("test").setFrom(10)
.setSize(20).setQuery(builder)
.execute().actionGet();
其中,from定義了目標數據的偏移值,size定義當前返回的數目。默認from為0,size為10,即所有的查詢默認僅僅返回前10條數據。這種查詢方式的缺點是越往后的分頁,執行效率越低。隨着from的增加,消耗時間也會增加。而且數據量越大,效果越明顯!也就是說,分頁的偏移值越大,執行分頁查詢時間就會越長!
Scroll分頁
Scroll API像傳統數據庫里的cursors(游標),可以允許我們檢索大量數據(甚至全部數據),它允許我們做一個初始階段搜索並且持續批量從Elasticsearch里拉取結果直到沒有結果剩下。相對於from-size的分頁來說,使用scroll可以模擬一個傳統數據的游標,記錄當前讀取的文檔信息位置。這個分頁的用法,不是為了實時查詢數據,而是為了一次性查詢大量的數據(甚至是全部的數據)。因為這個scroll相當於維護了一份當前索引段的快照信息,這個快照信息是你執行這個scroll查詢時的快照。在這個查詢后的任何新索引進來的數據,都不會在這個快照中查詢到。但是它相對於from-size,不是查詢所有數據然后剔除不要的部分,而是記錄一個讀取的位置,保證下一次快速繼續讀取
SearchResponse searchResponse = client.prepareSearch()
.setIndices("")
.setTypes("")
.setScroll(TimeValue.timeValueMinutes(1)) //游標維持時間
.setSearchType(SearchType.SCAN)//用Scan提高性能,但第一次不返回結果,返回scrollId
.setSize(1000)//實際返回的數量為1000*index的主分片數
.execute()
.actionGet();
TimeValue timeValue = new TimeValue(80000);
while(true) {
try {
//第一次查詢,只返回數量和一個scrollId
//注意第一次運行沒有結果
for (SearchHit hit : searchResponse.getHits().getHits()) {
//
}
//使用上次的scrollId繼續訪問
//初始搜索請求和每個后續滾動請求返回一個新的滾動ID,只有最近的滾動ID才能被使用
searchResponse = client.prepareSearchScroll(searchResponse.getScrollId()).setScroll(timeValue).execute().actionGet();
if (searchResponse.getHits().getHits().length == 0) {
break;
}
} catch (Exception e) {
}
}