Elasticsearch结合SpringBoot实现排序高亮查询

与SpringBoot集成

  • 初始化Sprint-boot工程,引入elasticsearch包,本篇文章中的spring-boot的版本为2.2.13.RELEASE,通过下面的方式引入elasticsearch
<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
  • 文件配置,新版本的Elasticsearch只需要在application.yml中加入下面的配置
spring:
  elasticsearch:
    rest:
      uris: http://localhost:9201 # es配置,如果是集群则需要配置多个
  • 通过上面两步就完成了spring和elasticsearch的集成,

操作Elasticsearch的API

配置Document

先要配置实体和ES的映射,通过在实体类中加入注解的方式来自动映射跟索引,我这里是配置了product索引和实体的映射

@Data
@Document(indexName = "product", type = "_doc")
public class ClusterEsProduct {

    @Id
    private Long id;

    @Field(type = FieldType.Long)
    private Long prodId;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String prodName;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
    private String prodDesc;

    @Field(type = FieldType.Float)
    private Float price;

    @Field(type = FieldType.Integer)
    private Integer stock;

    @Field(type = FieldType.Date)
    private Date createDate;

    private String prodDescHighlight;
}
  • 有了上面的实体映射就可以通过下面的两种方式来查询ES中的数据,具体方式如下

方式一ElasticsearchRestTemplate

  • 在Spring启动的时候自动注入了该Bean,它封装了操作Elasticsearch的增删改查API,这个比较好理解,像Spring封装的JDBCTemplateredisTemplate,这个功能也基本类似,屏蔽下层的API,提供简单易用的操作。下面就是使用它的分页功能的一个例子,实现了查询,排序,高亮,分页的功能
// 引入ElasticsearchRestTemplate
@Autowired
private ElasticsearchRestTemplate esRestTemplate;

public AggregatedPage<ClusterEsProduct> findByPage(String prodName) {
        // 完全匹配查询条件
        MatchQueryBuilder matchQueryBuilder1 = new MatchQueryBuilder("prod_desc", prodName);
        // 排序
        FieldSortBuilder price = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        // 高亮显示
        HighlightBuilder highlightBuilder
                = new HighlightBuilder().field("prod_desc").postTags("</red>").preTags("<red>");
        // 分页
        PageRequest pageRequest = PageRequest.of(0, 2);
        // 查询条件
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(matchQueryBuilder1);
        // 组装上述查询条件
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withSort(price)
                .withHighlightBuilder(highlightBuilder)
                .withPageable(pageRequest)
                .build();
        return esRestTemplate.queryForPage(searchQuery, ClusterEsProduct.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                // 改造返回的结果
                if (null != searchResponse.getHits()) {
                    // 获取命中的记录
                    SearchHit[] hits = searchResponse.getHits().getHits();
                    if (null != hits && hits.length > 0) {
                        List<ClusterEsProduct> productVoList = Lists.newArrayList();
                        Arrays.asList(hits).forEach(product -> {
                            Map<String, Object> source = product.getSourceAsMap();
                            ClusterEsProduct productVo = JSON.parseObject(JSON.toJSONString(source), ClusterEsProduct.class);
                            Map<String, HighlightField> highlightFieldMap = product.getHighlightFields();
                            if (CollectionUtil.isNotEmpty(highlightFieldMap)) {
                                // 设置高亮显示
                                productVo.setProdDescHighlight(highlightFieldMap.get("prod_desc").getFragments()[0].toString());

                            }
                            productVoList.add(productVo);
                        });
                        return new AggregatedPageImpl<>((List<T>) productVoList,
                                pageable,
                                searchResponse.getHits().getTotalHits());
                    } else {
                        log.info("没有命中记录");
                    }
                }
                return null;
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                return null;
            }
        });
    }

方式二ElasticsearchRepository

  • 这个是一个接口,类似于MyBatis的Mapper接口。该接口有两种方式来实现查询:一种是通过注解@Query,另外一种是通过findByxxx的方式
@Repository
public interface ClusterEsProductRepository extends ElasticsearchRepository<ClusterEsProduct, Long> {

    /**
     * 根据名称来查询
     * @param stock
     * @return
     */
    List<ClusterEsProduct> findClusterEsProductByStockGreaterThan(Integer stock);

    /**
     * 根据描述查询
     * @param prod_desc
     * @return
     */
    @Query(value = "{\"match\":{\"prod_desc\":\"?0\"}}")
    List<ClusterEsProduct> queryByProdDesc(String prod_desc);
}
  • 生成接口的方式
    生成接口

总结

  • 通过把Elasticsearch集成到Spring中来,能够灵活的使用Elasticsearch的API,归根结底,Spring的API也是基于DSL来编写,所以还是对底层的操作API比较熟悉。通过上面的介绍,操作的方式有两种,一种是通过ElasticsearchRestTemplate,另外一种是通过ElasticsearchRepository,可以根据自己的需要决定采用哪一种。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值