SpringBoot 整合 Elasticsearch深度分页查询
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 */
还没有评论,来说两句吧...