您好,登錄后才能下訂單哦!
這篇文章給大家介紹ES解決深分頁問題以及實(shí)現(xiàn)Scroll 查詢 API的示例分析,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
ES 普通的分頁查詢有深分頁限制,默認(rèn)是10000條。(因?yàn)樵酵竺娣衷胶膬?nèi)存)所以要查詢1萬條以后的數(shù)據(jù),要不就縮小查詢范圍,要不用別的方法。
ES 提供了 scroll 查詢。第一次查詢獲取到scroll_id,下次查詢通過scroll_id直接查詢。scroll相當(dāng)于維護(hù)了一份當(dāng)前索引段的快照信息,這個快照信息是你執(zhí)行這個scroll查詢時的快照。在這個查詢后的任何新索引進(jìn)來的數(shù)據(jù),都不會在這個快照中查詢到。但是它相對于from和size,不是查詢所有數(shù)據(jù)然后剔除不要的部分,而是記錄一個讀取的位置,保證下一次快速繼續(xù)讀取。而且也不能排序,只能按默認(rèn)的文檔順序,比較適合查詢掃描全量數(shù)據(jù)。
private static void scrollSearch(String indexName, String typeName, String... ids) { IdsQueryBuilder qb = QueryBuilders.idsQuery().addIds(ids); SearchResponse sResponse = client.prepareSearch(indexName) .setTypes(typeName) .setQuery(qb) .setScroll(new TimeValue(5000)) .setSize(50) .execute() .actionGet(); int tShards = sResponse.getTotalShards(); long timeCost = sResponse.getTookInMillis(); int sShards = sResponse.getSuccessfulShards(); System.out.println(tShards+","+timeCost+","+sShards); while (true) { SearchHits hits = sResponse.getHits(); SearchHit[] hitArray = hits.getHits(); for(int i = 0; i < hitArray.length; i++) { SearchHit hit = hitArray[i]; Map<String, Object> fields = hit.getSource(); for(String key : fields.keySet()) { System.out.println(key); System.out.println(fields.get(key)); } } sResponse = client.prepareSearchScroll(sResponse.getScrollId()).setScroll(new TimeValue(5000)).execute().actionGet(); //Break condition: No hits are returned if (sResponse.getHits().getHits().length == 0) { break; } } }
// 接口定義 /** * Scroll 游標(biāo)全量數(shù)據(jù)查詢 (不支持排序,只按照doc_id排序) * * @param clazz 實(shí)體類類型 * @param query 查詢參數(shù) * @param scrollId 游標(biāo) * @param size 一次拿取數(shù)據(jù)多少。 * @param <T> * @return */ <T extends EEntity> EsScrollResponse<T> listByQueryScroll(Class<T> clazz, IQuery query, String scrollId,int size); // 具體實(shí)現(xiàn) @Override public <T extends EEntity> EsScrollResponse<T> listByQueryScroll(Class<T> clazz, IQuery query, String scrollId, int size) { // 參數(shù)校驗(yàn) if (size < 1 || size > 200) { throw new RuntimeException("ES 查詢一次請求的數(shù)了超出范圍,請在 1-200 之間"); } // 返回結(jié)果初始化 EsScrollResponse response = new EsScrollResponse<>(); List<T> result = new ArrayList<>(); // 獲取文檔信息 Document document = clazz.getAnnotation(Document.class); // 全局使用的查詢返回參數(shù)初始化。 SearchResponse searchResponse = null; // 第一次查詢沒有游標(biāo),獲取數(shù)據(jù)并記錄游標(biāo) if (StringUtils.isEmpty(scrollId)) { SearchRequestBuilder searchRequestBuilder = esDataSource.getClient().prepareSearch(document.indexName()).setTypes(document.type()).setQuery(query.buildQuery()).setScroll(TimeValue.timeValueMinutes(ES_TIME_OUT_MINUTES)).setSize(size); searchResponse = searchRequestBuilder.setTimeout(TimeValue.timeValueMinutes(ES_TIME_OUT_MINUTES)).execute().actionGet(); } else { // 有游標(biāo)按游標(biāo)進(jìn)行查詢 SearchScrollRequestBuilder searchScrollRequestBuilder = esDataSource.getClient().prepareSearchScroll(scrollId).setScroll(TimeValue.timeValueMinutes(ES_TIME_OUT_MINUTES)); searchResponse = searchScrollRequestBuilder.execute().actionGet(); } // 處理返回結(jié)果 for (SearchHit hit : searchResponse.getHits()) { T rt = JSON.parseObject(hit.getSourceAsString(), clazz); result.add(rt); } response.setData(result); response.setScrollId(searchResponse.getScrollId()); return response; } /** * ES Scroll 查詢的封裝實(shí)體 */ @Data public class EsScrollResponse<T> { /** * 存放數(shù)據(jù) */ private List<T> data; /** * 指定游標(biāo) */ private String scrollId; }
分頁方式 | 說明 | 優(yōu)點(diǎn) | 缺點(diǎn) | 場景 |
---|---|---|---|---|
from + size | 常用的分頁方式,指定分頁大小和偏移量可以直接獲取到需要的數(shù)據(jù)。但內(nèi)存消耗特別大,且速度很一般,當(dāng)我們指定from = 100000,size = 10 的時候,每個node都會取出top 100000的數(shù)據(jù),再進(jìn)行匯總排序,假設(shè)3個node,那么就需要取出3*100000條數(shù)據(jù)進(jìn)行排序后,再取top10的數(shù)據(jù)進(jìn)行返回。所以ES默認(rèn)的from+size的限制設(shè)置為10000。在數(shù)據(jù)量到達(dá)十萬級百萬級的時候這種分頁方式顯然不合理。 | 數(shù)據(jù)量小的情況使用最方便,靈活性好,實(shí)現(xiàn)簡單 | 內(nèi)存消耗大,速度一般,數(shù)據(jù)量大的情況面臨深度分頁問題 | 數(shù)據(jù)量較小且能容忍深度分頁問題 |
scroll(游標(biāo)) | 一種快照的查詢形式,快照一旦形成,本次滾動查詢內(nèi)便無法查出來新增的那些數(shù)據(jù),而且scroll是無法進(jìn)行排序的,也無法指定from,那么我們想查看指定頁碼的數(shù)據(jù)就必須將該頁數(shù)據(jù)之前的全部數(shù)據(jù)取出來再進(jìn)行丟棄,所以scroll一般用于導(dǎo)出全量數(shù)據(jù)。 | 導(dǎo)出全量數(shù)據(jù)時性能最好 | 無法反應(yīng)數(shù)據(jù)的實(shí)時性(因?yàn)槭强煺瞻姹荆?,維護(hù)成本高,需要維護(hù)一個 scroll_id,且不支持排序,只按照doc_id排序 | 全量數(shù)據(jù)的導(dǎo)出 |
關(guān)于ES解決深分頁問題以及實(shí)現(xiàn)Scroll 查詢 API的示例分析就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。