SpringBoot 整合 Elasticsearch深度分頁查詢


es 查詢共有4種查詢類型

QUERY_AND_FETCH: 

   主節點將查詢請求分發到所有的分片中,各個分片按照自己的查詢規則即詞頻文檔頻率進行打分排序,然后將結果返回給主節點,主節點對所有數據進行匯總排序然后再返回給客戶端,此種方式只需要和es交互一次。

      這種查詢方式存在數據量和排序問題,主節點會匯總所有分片返回的數據這樣數據量會比較大,二是各個分片上的規則可能不一致。

QUERY_THEN_FETCH: 

主節點將請求分發給所有分片,各個分片打分排序后將數據的id和分值返回給主節點,主節點收到后進行匯總排序再根據排序后的id到對應的節點讀取對應的數據再返回給客戶端,此種方式需要和es交互兩次。

      這種方式解決了數據量問題但是排序問題依然存在而且是es的默認查詢方式

DEF_QUERY_AND_FETCH 和 DFS_QUERY_THEN_FETCH: 

  將各個分片的規則統一起來進行打分。解決了排序問題但是DFS_QUERY_AND_FETCH仍然存在數據量問題,DFS_QUERY_THEN_FETCH兩種噢乖你問題都解決但是效率是最差的。

 

Maven依賴:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>2.0.5.RELEASE</version> 
</dependency>

 

yml配置:

spring:
    data:
        elasticsearch:
             cluster-name: elasticsearch
             cluster-nodes: 127.0.0.1:9300

 

測試代碼:

  1 /**
  2  * @author 宮新程
  3  * @since 2018/10/24 12:29
  4  */
  5 @RunWith(SpringRunner.class)
  6 @SpringBootTest
  7 @Slf4j
  8 public class GoodsItemLaunchEsTest {
  9 
 10   // 查詢條件
 11   private static final String ES_SEARCH_ITEM_NAME = "itemName";
 12   private static final String ES_SEARCH_ITEM_MODEL = "itemModel";
 13   private static final String ES_SEARCH_PRODUCT_CODE = "productCode";
 14   private static final String ES_SEARCH_OPER_FLAG = "oper_flag";
 15 
 16   @Resource private ElasticsearchTemplate elasticsearchTemplate;
 17   @Resource private EsManager esManager;
 18 
 19   /** ES創建基礎表 */
 20   @Test
 21   public void createIndex() {
 22     elasticsearchTemplate.createIndex(EsGoodsItemLaunchDto.class);
 23     elasticsearchTemplate.putMapping(EsGoodsItemLaunchDto.class);
 24   }
 25 
 26   /** ES刪除表 */
 27   @Test
 28   public void deleteIndex() {
 29     this.elasticsearchTemplate.deleteIndex(EsGoodsItemLaunchDto.class);
 30   }
 31 
 32   /** 插入測試數據 */
 33   @Test
 34   public void insertData() {
 35 
 36     List<IndexQuery> queryList = new ArrayList<>();
 37 
 38     for (int i = 0; i < 10000; i++) {
 39       EsGoodsItemLaunchDto dto = new EsGoodsItemLaunchDto();
 40       dto.setId(i);
 41       dto.setItemId(i);
 42       dto.setItemSkuId(i);
 43       dto.setItemName(i % 2 == 0 ? "洗衣機" + i : "空調" + i);
 44       dto.setCustomerSellerCode("CustomerSellerCode" + i);
 45       dto.setCustomerName("CustomerName" + i);
 46       dto.setMemberSellerCode("MemberSellerCode" + i);
 47       dto.setMemberName("MemberName" + i);
 48       dto.setProductCode("ProductCode" + i);
 49       dto.setItemModel("ItemModel" + i);
 50       dto.setProductGroupName("ProductGroupName" + i);
 51       dto.setProductGroupCode("ProductGroupCode" + i);
 52       dto.setBrandId(i * 2);
 53       dto.setBrandName("BrandName" + i);
 54       dto.setGmCode(((int) Math.random() * 10000) + "");
 55       dto.setUpdateTime(new Date());
 56       dto.setMemberId(i * 5);
 57       dto.setCustomerId(i * 6);
 58 
 59       IndexQuery indexQuery =
 60           new IndexQueryBuilder()
 61               .withId(String.valueOf(dto.getId()))
 62               .withObject(dto)
 63               .withIndexName(esManager.index4r(EsGoodsItemLaunchDto.class))
 64               .build();
 65 
 66       queryList.add(indexQuery);
 67 
 68       if (queryList.size() == 1000) {
 69         this.elasticsearchTemplate.bulkIndex(queryList);
 70         queryList.clear();
 71       }
 72     }
 73 
 74     // 必須加if判斷否則報異常:
 75     // org.elasticsearch.action.ActionRequestValidationException:
 76     // Validation Failed: 1:no requests added;
 77     if (queryList.size() > 0) {
 78       // 保存剩余數據 (沒被1000整除)
 79       elasticsearchTemplate.bulkIndex(queryList);
 80     }
 81   }
 82 
 83   @Test
 84   public void search() {
 85     int pageNum = 2;
 86     int pageSize = 5;
 87 
 88     BoolQueryBuilder filter = QueryBuilders.boolQuery();
 89     // 注意一定要小寫處理 toLowerCase()
 90     String codeOrName = "ProductCode100".toLowerCase();
 91     BoolQueryBuilder boolQueryLike = QueryBuilders.boolQuery();
 92     // 分詞查詢 商品名稱
 93     MultiMatchQueryBuilder queryBuilder =
 94         QueryBuilders.multiMatchQuery(codeOrName, ES_SEARCH_ITEM_NAME);
 95     // 商品型號
 96     QueryBuilder itemModel =
 97         QueryBuilders.wildcardQuery(ES_SEARCH_ITEM_MODEL, "*" + codeOrName + "*");
 98     // 產品編碼
 99     QueryBuilder productCode =
100         QueryBuilders.wildcardQuery(ES_SEARCH_PRODUCT_CODE, "*" + codeOrName + "*");
101     boolQueryLike.should(queryBuilder);
102     boolQueryLike.should(itemModel);
103     boolQueryLike.should(productCode);
104     filter.must(boolQueryLike);
105 
106     // 判斷ES表的 oper_flag 不等於 D
107     filter.mustNot(QueryBuilders.termQuery(ES_SEARCH_OPER_FLAG, "D"));
108 
109     SearchQuery searchQuery = new NativeSearchQuery(filter);
110     searchQuery.addIndices(esManager.index4r(EsGoodsItemLaunchDto.class));
111     Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
112     searchQuery.setPageable(pageable);
113 
114     // 深度查詢分頁
115     Page<EsGoodsItemLaunchDto> result =
116         this.elasticsearchTemplate.startScroll(5000, searchQuery, EsGoodsItemLaunchDto.class);
117 
118     for (int i = 0; i < pageNum - 1; i++) {
119       elasticsearchTemplate.continueScroll(
120           ((ScrolledPage) result).getScrollId(), 5000, EsGoodsItemLaunchDto.class);
121     }
122 
123     log.info("=====================================");
124     result
125         .getContent()
126         .forEach(
127             (dto) -> {
128               log.info("ItemName:{}", dto.getItemName());
129             });
130     log.info("總記錄數:{}", result.getTotalElements());
131     log.info("當前頁碼數:{}", pageNum);
132     log.info("每頁顯示條數:{}", pageSize);
133     log.info("=====================================");
134   }
135 }
136 /* 輸出結果:
137 <============================>
138 <ItemName:空調1001>
139 <ItemName:洗衣機1004>
140 <ItemName:洗衣機1006>
141 <ItemName:空調1007>
142 <ItemName:洗衣機1008>
143 <總記錄數:11>
144 <當前頁碼數:2>
145 <每頁顯示條數:5>
146 <============================>
147 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM