作者:千鋒老魏
源碼地址:https://github.com/qfjiaoyan/elasticsearch-examples
ES對於from+size的個數是有限制的,二者之和不能超過1w。當所請求的數據總量大於1w時,可用scroll來代替from+size。
1.7.1 原理
ES的搜索是分2個階段進行的,即Query階段和Fetch階段。 Query階段比較輕量級,通過查詢倒排索引,獲取滿足查詢結果的文檔ID列表。 而Fetch階段比較重,需要將每個shard的結果取回,在協調結點進行全局排序。 通過From+size這種方式分批獲取數據的時候,隨着from加大,需要全局排序並丟棄的結果數量隨之上升,性能越來越差。
而Scroll查詢,先做輕量級的Query階段以后,免去了繁重的全局排序過程。 它只是將查詢結果集,也就是doc id列表保留在一個上下文里, 之后每次分批取回的時候,只需根據設置的size,在每個shard內部按照一定順序(默認doc_id續), 取回這個size數量的文檔即可。
1.7.2 使用場景
由此也可以看出scroll不適合支持那種實時的和用戶交互的前端分頁工作,其主要用途用於從ES集群分批拉取大量結果集的情況,一般都是offline的應用場景。 比如需要將非常大的結果集拉取出來,存放到其他系統處理,或者需要做大索引的reindex等等。 不要把 scroll 用於實時請求,它主要用於大數據量的場景。例如:將一個索引的內容索引到另一個不同配置的新索引中。
1.7.3 JAVA代碼示例
例如滾動查詢所有文檔:
POST 127.0.0.1:9200/my_index/_search?scroll=1m { "query": { "match_all": { } }, "sort": [ "_doc" ] }
清除scroll
雖然我們在設置開啟scroll時,設置了一個scroll的存活時間,但是如果能夠在使用完順手關閉,可以提早釋放資源,降低ES的負擔.
DELETE 127.0.0.1:9200/_search/scroll { "scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAdsMqFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbDKRZlZGUwSWpSVlJqeVJiN1dBWHNpUG1RAAAAAABpX2sWclBEekhiRVpSRktHWXFudnVaQ3dIQQAAAAAAaV9qFnJQRHpIYkVaUkZLR1lxbnZ1WkN3SEEAAAAAAGlfaRZyUER6SGJFWlJGS0dZcW52dVpDd0hB" }
JAVA代碼示例:com.qianfeng.elasticsearch.query.impl.BaseQueryImpl
@Override public void scroll Query(StringindexName,StringtypeName) throws IOException{ SearchRequest searchRequest= new SearchRequest(indexName); searchRequest.types(typeName); //初始化scroll //值不需要足夠長來處理所有數據—它只需要足夠長來處理前一批結果。每個滾動請求(帶有滾動參數)設置一個新的過期時間。 final Scroll scroll= new Scroll(TimeValue.timeValueMinutes(1L));//設定滾動時間間隔 searchRequest.scroll(scroll); SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); searchSourceBuilder.query(matchAllQuery()); searchSourceBuilder.size(5);//設定每次返回多少條數據 searchRequest.source(searchSourceBuilder); log.info("string:"+searchRequest.source()); SearchResponse searchResponse=null; try{ searchResponse=restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT); }catch(IOExceptione){ e.printStackTrace(); } String scrollId=searchResponse.getScrollId(); SearchHit[] searchHits=searchResponse.getHits().getHits(); System.out.println("-----首頁-----"); for(SearchHitsearchHit: searchHits){ System.out.println(searchHit.getSourceAsString()); } //遍歷搜索命中的數據,直到沒有數據 while(searchHits!=null&&searchHits.length>0){ SearchScrollRequest scrollRequest=new SearchScrollRequest(scrollId); scrollRequest.scroll(scroll); log.info("string:"+scrollRequest.toString()); try{ searchResponse=restHighLevelClient.scroll(scrollRequest,RequestOptions.DEFAULT); }catch(IOExceptione){ e.printStackTrace(); } scrollId=searchResponse.getScrollId(); searchHits=searchResponse.getHits().getHits(); if(searchHits!=null&&searchHits.length>0){ System.out.println("-----下一頁-----"); for(SearchHitsearchHit: searchHits){ System.out.println(searchHit.getSourceAsString()); } } } //清除滾屏 ClearScrollRequest clearScrollRequest=new ClearScrollRequest(); clearScrollRequest.addScrollId(scrollId); //也可以選擇setScrollIds()將多個scrollId一起使用 ClearScrollResponse clearScrollResponse=null; try{ clearScrollResponse=restHighLevelClient.clearScroll(clearScrollRequest,RequestOptions.DEFAULT); }catch(IOExceptione){ e.printStackTrace(); } boolean succeeded=clearScrollResponse.isSucceeded(); System.out.println("succeeded:"+succeeded); }
演示用例:com.qianfeng.elasticsearch.test.document.testIdsQuery
@Test public void testScrollQuery() throws IOException { baseQuery.scrollQuery(indexName,type); }
演示效果:
源碼地址:https://github.com/qfjiaoyan/elasticsearch-examples
————————————————
版權聲明:本文為CSDN博主「天珊雪」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_29192141/article/details/112382067