Elasticsearch中數據都存儲在分片中,當執行搜索時每一個分片獨立搜索後,數據再通過整合返回。那麼,若是要實現分頁查詢該怎麼辦呢?
更多內容參考Elasticsearch資料彙總php
按照通常的查詢流程來講,若是我想查詢前10條數據:html
那麼當我想要查詢第10條到第20條的數據該怎麼辦呢?這個時候就用到分頁查詢了。java
"淺"分頁的概念是小博主本身定義的,能夠理解爲簡單意義上的分頁。它的原理很簡單,就是查詢前20條數據,而後截斷前10條,只返回10-20的數據。這樣其實白白浪費了前10條的查詢。curl
查詢的方法如:elasticsearch
{ "from" : 0, "size" : 10, "query" : { "term" : { "user" : "kimchy" } } }
其中,from定義了目標數據的偏移值,size定義當前返回的事件數目。
默認from爲0,size爲10,即全部的查詢默認僅僅返回前10條數據。maven
作過測試,越日後的分頁,執行的效率越低。
經過下圖能夠看出,刨去一些異常的數據,整體上仍是會隨着from的增長,消耗時間也會增長。並且數據量越大,效果越明顯!ide
相對於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能夠繼續查詢(實際上這個ID會很長哦!):
curl -XGET 'localhost:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'
注意,我在使用1.4版本的ES時,只支持把參數放在URL路徑裏面,不支持在JSON body中使用。
有個頗有意思的事情,細心的會發現,這個ID實際上是經過base64編碼的:
cXVlcnlUaGVuRmV0Y2g7MTY7MjI3NTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzQ6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgwOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4MTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODM6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgyOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg5OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4NDp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODU6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjc4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3OTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzA7
若是使用解碼工具能夠看到:
queryThenFetch;16;2275:vtXKJ8lnQImdiwcDtPT-kA;2274:vtXKJ8lnQImdiwcDtPT-kA;2280:vtXKJ8lnQImdiwcDtPT-kA;2281:vtXKJ8lnQImdiwcDtPT-kA;2283:vtXKJ8lnQImdiwcDtPT-kA;2282:vtXKJ8lnQImdiwcDtPT-kA;2286:vtXKJ8lnQImdiwcDtPT-kA;2287:vtXKJ8lnQImdiwcDtPT-kA;2289:vtXKJ8lnQImdiwcDtPT-kA;2284:vtXKJ8lnQImdiwcDtPT-kA;2285:vtXKJ8lnQImdiwcDtPT-kA;2288:vtXKJ8lnQImdiwcDtPT-kA;2276:vtXKJ8lnQImdiwcDtPT-kA;2277:vtXKJ8lnQImdiwcDtPT-kA;2278:vtXKJ8lnQImdiwcDtPT-kA;2279:vtXKJ8lnQImdiwcDtPT-kA;0;
雖然搞不清楚裏面是什麼內容,可是看到了一堆規則的鍵值對,老是讓人興奮一下!
首先呢,須要在java中引入elasticsearch-jar,好比使用maven:
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>1.4.4</version> </dependency>
而後初始化一個client對象:
private static TransportClient client; private static String INDEX = "index_name"; private static String TYPE = "type_name"; public static TransportClient init(){ Settings settings = ImmutableSettings.settingsBuilder() .put("client.transport.sniff", true) .put("cluster.name", "cluster_name") .build(); client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress("localhost",9300)); return client; } public static void main(String[] args) { TransportClient client = init(); //這樣就可使用client執行查詢了 }
而後就是建立兩個查詢過程了 ,下面是from-size分頁的執行代碼:
System.out.println("from size 模式啓動!"); Date begin = new Date(); long count = client.prepareCount(INDEX).setTypes(TYPE).execute().actionGet().getCount(); SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(QueryBuilders.matchAllQuery()); for(int i=0,sum=0; sum<count; i++){ SearchResponse response = requestBuilder.setFrom(i).setSize(50000).execute().actionGet(); sum += response.getHits().hits().length; System.out.println("總量"+count+" 已經查到"+sum); } Date end = new Date(); System.out.println("耗時: "+(end.getTime()-begin.getTime()));
下面是scroll分頁的執行代碼,注意啊!scroll裏面的size是相對於每一個分片來講的,因此實際返回的數量是:分片的數量*size
System.out.println("scroll 模式啓動!"); begin = new Date(); SearchResponse scrollResponse = client.prepareSearch(INDEX) .setSearchType(SearchType.SCAN).setSize(10000).setScroll(TimeValue.timeValueMinutes(1)) .execute().actionGet(); count = scrollResponse.getHits().getTotalHits();//第一次不返回數據 for(int i=0,sum=0; sum<count; i++){ scrollResponse = client.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()));
我這裏總的數據有33萬多,分別以每頁5000,10000,50000的數據量請求,獲得以下的執行時間:
能夠看到僅僅30萬,就相差接近一倍的性能,更況且是現在的大數據環境...所以,若是想要對全量數據進行操做,快換掉fromsize,使用scroll吧!
1 簡書:elasticsearch 的滾動(scroll)
2 16php:Elasticsearch Scroll API詳解
3 elastic:from-size查詢
4 elastic:scroll query