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 */