ElasticSearch查詢—分頁查詢詳解
Elasticsearch中數據都存儲在分片中,當執行搜索時每個分片獨立搜索后,數據再經過整合返回。那么,如何實現分頁查詢呢?
按照一般的查詢流程來說,如果我想查詢前10條數據:
1)客戶端請求發給某個節點
2)節點轉發給個個分片,查詢每個分片上的前10條
3)結果返回給節點,整合數據,提取前10條
4)返回給請求客戶端
那么當我想要查詢第10條到第20條的數據該怎么辦呢?這個時候就用到分頁查詢了。
在ElasticSearch中實現分頁查詢的方式有兩種,分別為深度分頁(from-size)和快照分頁(scroll)
1.深度分頁(from-size)
原理很簡單,就是查詢前20條數據,然后截斷前10條,只返回10-20的數據。這樣其實白白浪費了前10條的查詢。
查詢API如下:
{
"from" : 0, "size" : 10,
"query" : {
"term" : { "user" : "kimchy" }
}
}
其中,from定義了目標數據的偏移值,size定義當前返回的事件數目。默認from為0,size為10,即所有的查詢默認僅僅返回前10條數據。
做過測試,越往后的分頁,執行的效率越低。也就是說,分頁的偏移值越大,執行分頁查詢時間就會越長!
2. 快照分頁(scroll)
相對於from和size的分頁來說,使用scroll可以模擬一個傳統數據的游標,記錄當前讀取的文檔信息位置。這個分頁的用法,不
是為了實時查詢數據,而是為了一次性查詢大量的數據(甚至是全部的數據)。因為這個scroll相當於維護了一份當前索引段的快照
信息,這個快照信息是你執行這個scroll查詢時的快照。在這個查詢后的任何新索引進來的數據,都不會在這個快照中查詢到。但是
它相對於from和size,不是查詢所有數據然后剔除不要的部分,而是記錄一個讀取的位置,保證下一次快速繼續讀取。
查詢API如下:
curl -XGET 'localhost:9200/twitter/tweet/_search?scroll=1m' -d '
{
"query": {
"match" : {
"title" : "elasticsearch"
}
}
}
該查詢會自動返回一個_scroll_id,通過這個id(經過base64編碼)可以繼續查詢。
curl -XGET '集群節點IP:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'
3.java API實現
public class PageQueryInElasticSearch {
private static String index = "test_index35";
private static String type = "test_type35";
public static void main(String[] args) {
Settings settings = ImmutableSettings.settingsBuilder().put("cluster.name", "contentmanageres")
.put("client.transport.sniff", true)// 開啟ES嗅探功能,確保集群連上多個節點
.build();
// 創建客戶端
TransportClient transportClient = new TransportClient(settings);
// 添加es的節點信息,可以添加1個或多個
TransportAddress transportAddress = new InetSocketTransportAddress("172.17.168.96", 9300);
transportClient.addTransportAddresses(transportAddress);
// 連接到的節點
ImmutableList<DiscoveryNode> connectedNodes = transportClient.connectedNodes();
for (DiscoveryNode discoveryNode : connectedNodes) {
System.out.println(discoveryNode.getHostAddress());
}
System.out.println("from size 模式啟動!");
Date begin = new Date();
long count = transportClient.prepareCount(index).setTypes(type).execute().actionGet().getCount();//獲取所有記錄
SearchRequestBuilder requestBuilder = transportClient.prepareSearch(index).setTypes(type).setQuery(QueryBuilders.matchAllQuery());
for(int i=0,sum=0; sum<count; i++){
SearchResponse response = requestBuilder.setFrom(i).setSize(5000).execute().actionGet();
sum += response.getHits().hits().length;
System.out.println("總量"+count+" 已經查到"+sum);
}
Date end = new Date();
System.out.println("耗時: "+(end.getTime()-begin.getTime()));
System.out.println("scroll 模式啟動!");
begin = new Date();
SearchResponse scrollResponse = transportClient.prepareSearch(index)
.setSearchType(SearchType.SCAN) //在ES 5.x版本中不存在SearchType.SCAN用法,可以用addSort(SortBuilders.fieldSort("_doc"))
.setSize(1000) //實際返回的數量為size*index的主分片個數(在ES 5.x版本中,返回的數據量就是參數中指定的數據量)
.setScroll(TimeValue.timeValueMinutes(1))
.execute().actionGet();
count = scrollResponse.getHits().getTotalHits();//獲取所有記錄,第一次不返回數據(在ES 5.x版本中,第一次有數據返回)
for(int sum=0; sum<count; ){
scrollResponse = transportClient.prepareSearchScroll(scrollResponse.getScrollId())
.setScroll(TimeValue.timeValueMinutes(8))
.execute().actionGet();
sum += scrollResponse.getHits().hits().length;
System.out.println("總量"+count+" 已經查到"+sum);
}
end = new Date();
System.out.println("耗時: "+(end.getTime()-begin.getTime()));
}
}
相關鏈接如下:https://www.cnblogs.com/xing901022/archive/2016/03/16/5284902.html
http://www.jianshu.com/p/627887e3eea3
---------------------
作者:午夜陽光psb
來源:CSDN
原文:https://blog.csdn.net/u013514928/article/details/78749419
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!