zoukankan      html  css  js  c++  java
  • 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 */
  • 相关阅读:
    Qt 学习之路 :自定义只读模型
    Qt 学习之路:QSortFilterProxyModel
    Qt 学习之路 :可视化显示数据库数据
    Qt 学习之路 :访问网络(4)
    Qt 学习之路:QFileSystemModel
    高级Bash脚本编程指南
    CGI
    shell学习
    【shell】while read line 与for循环的区别
    管道技巧-while read line
  • 原文地址:https://www.cnblogs.com/gxc6/p/9843690.html
Copyright © 2011-2022 走看看