在公司的操作es進行查詢數據時,es默認分頁且只返回十條數據,並且size最大只能傳10000,這種查詢方式稱之為深度分頁的方式也就是用 from 和 size 參數分頁查詢。由於我們當時開發任務緊急,所以在需要獲取全量數據時就直接更改了這一限制,改為了10000000(一千萬)條。但是這一方式可能在之后項目上線后隨着數據量逐漸增多的情況下可能會對es服務造成一定隱患,因此需要改為官方推薦的scroll(游標)方式查詢獲取全量數據。
對於深度分頁獲取大量數據的劣勢官方文檔已給出了較為詳細的解釋,並且官方建議使用scroll的方式來進行全量數據的獲取。具體如下:
摘自 《Elasticsearch: 權威指南》→ 基礎入門 → 搜索——最基本的工具 → 分頁
摘自 《Elasticsearch: 權威指南》→
相對於from和size的分頁來說,可以把scroll理解為關系型數據庫里的 cursor(游標),不是查詢所有數據然后剔除不要的部分,而是記錄了當前讀取的文檔信息位置,保證下一次快速繼續讀取。也可以理解為維護了一份當前索引段的快照信息,這個快照信息是你執行這個scroll查詢時的快照。在這個查詢后的任何新索引進來的數據,都不會在這個快照中查詢到。因此scroll 並不適合用來做實時搜索,而更適用於一次性查詢大量的數據(甚至是全部的數據)。
摘自 《Elasticsearch: 權威指南》→
es的刪除機制為根據條件查詢出來再進行刪除操作,在閱讀spring-data-elasticsearch包中的elasticsearchTemplate源碼時,發現該類中的刪除方法也是使用的scroll方式獲取了全量數據再進行刪除,因此scroll游標的方式查詢數據更適用於全量數據的獲取。以下為elasticsearchTemplate源碼:
1 @Override 2 public <T> void delete(DeleteQuery deleteQuery, Class<T> clazz) { 3 4 String indexName = !StringUtils.isEmpty(deleteQuery.getIndex()) ? deleteQuery.getIndex() 5 : getPersistentEntityFor(clazz).getIndexName(); 6 String typeName = !StringUtils.isEmpty(deleteQuery.getType()) ? deleteQuery.getType() 7 : getPersistentEntityFor(clazz).getIndexType(); 8 Integer pageSize = deleteQuery.getPageSize() != null ? deleteQuery.getPageSize() : 1000; 9 Long scrollTimeInMillis = deleteQuery.getScrollTimeInMillis() != null ? deleteQuery.getScrollTimeInMillis() 10 : 10000l; 11 12 SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(deleteQuery.getQuery()).withIndices(indexName) 13 .withTypes(typeName).withPageable(PageRequest.of(0, pageSize)).build(); 14 15 SearchResultMapper onlyIdResultMapper = new SearchResultMapper() { 16 @Override 17 public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) { 18 List<String> result = new ArrayList<String>(); 19 for (SearchHit searchHit : response.getHits().getHits()) { 20 String id = searchHit.getId(); 21 result.add(id); 22 } 23 if (result.size() > 0) { 24 return new AggregatedPageImpl<T>((List<T>) result, response.getScrollId()); 25 } 26 return new AggregatedPageImpl<T>(Collections.EMPTY_LIST, response.getScrollId()); 27 } 28 }; 29 30 Page<String> scrolledResult = startScroll(scrollTimeInMillis, searchQuery, String.class, onlyIdResultMapper); 31 BulkRequestBuilder bulkRequestBuilder = client.prepareBulk(); 32 List<String> ids = new ArrayList<String>(); 33 34 do { 35 ids.addAll(scrolledResult.getContent()); 36 scrolledResult = continueScroll(((ScrolledPage<T>)scrolledResult).getScrollId(), scrollTimeInMillis, String.class, onlyIdResultMapper); 37 } while(scrolledResult.getContent().size() != 0); 38 39 for (String id : ids) { 40 bulkRequestBuilder.add(client.prepareDelete(indexName, typeName, id)); 41 } 42 43 if (bulkRequestBuilder.numberOfActions() > 0) { 44 bulkRequestBuilder.execute().actionGet(); 45 } 46 47 clearScroll(((ScrolledPage<T>) scrolledResult).getScrollId()); 48 }
故此記錄在查詢全量數據時使用scroll游標方式查詢數據更好。


摘自 《
摘自 《