Elasticsearch结合springboot实现搜索功能

本文介绍了如何在SpringBoot项目中使用Elasticsearch进行各种搜索操作,包括全匹配、模糊匹配、多字段匹配、精确查询、范围查询、地理位置查询、布尔查询、排序、分页、高亮和根据相关度评分的函数查询,以及如何配置和使用RestHighLevelClient进行API调用。
摘要由CSDN通过智能技术生成

Elasticsearch可以通过对doc文档的操作实现对不同条件下的搜索,排序,打分等等功能,这个功能不仅可以用dsl语句在控制台的里实现,也可以使用springboot提供的api用java代码实现。

1 事先准备

1.1导入相关依赖

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

1.2配置环境

spring:
  elasticsearch:
    rest:
      uris: 192.168.184.100:9200 #输入你部署好的es服务地址
  data:
    elasticsearch:
      repositories:
        enabled: true

为了在后面代码中更好使用es工具,我们通过配置类将RestHighLevelClient添加到spring容器中管理。

    @Value("${spring.elasticsearch.rest.uris}")
    private String uris;

    @Bean
    public RestHighLevelClient elasticsearchClient() {
        ClientConfiguration configuration = ClientConfiguration.builder()
                .connectedTo(uris)
                .build();
        return RestClients.create(configuration).rest();
    }

2 代码编写

2.1查询所有

 @Test
    public void MatchAllTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.matchAllQuery());
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

我将结果处理抽取出来进行单独处理

public void showRes(SearchResponse res){
        SearchHits hits = res.getHits();
        int length = (int) hits.getTotalHits().value;
        System.out.println("共查询到 "+length+" 条数据");
        //获取所有查询数据
        SearchHit[] hits1 = hits.getHits();
        for (SearchHit documentFields : hits1) {
            //将doc转为Object对象
            String sourceAsString = documentFields.getSourceAsString();
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);
            //高亮显示搜索内容
            if(!CollectionUtils.isEmpty(highlightFields)){
                HighlightField highlightField = highlightFields.get("name");
                Text[] fragments = highlightField.getFragments();
                String s = fragments[0].toString();
                hotelDoc.setName(s);
            }
            System.out.println(hotelDoc);
        }
    }

其他查询也都大差不差,这里全部贴上代码:

 /**
     * match模糊匹配
     * @throws IOException
     */
    @Test
    public void MatchTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.matchQuery("name","如家"));
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

    /**
     * multi_match 会匹配多个字段信
     * @throws IOException
     */
    @Test
    public void MultiMatchTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.multiMatchQuery("外滩如家酒店","brand","name","business"));
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

    /**
     * term精确查询,必须与传入的值完全相同才能匹配成功
     * @throws IOException
     */
    @Test
    public void TermTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.termQuery("id","434082"));
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

    /**
     * range范围查询
     * @throws IOException
     */
    @Test
    public void rangeTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.rangeQuery("score").gt(10).lt(30));
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

    //distance查询地理位置
    @Test
    public void distanceTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders
                .geoDistanceQuery("location") //具体根据什么信息查询
                .distance("3km") //查询范围
                .point(31.220706,121.498769)); //范围中心坐标
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }
 //复合查询 boolean
    @Test
    public void boolTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.boolQuery()
                .must(QueryBuilders.matchQuery("name","如家"))
                .filter(QueryBuilders.rangeQuery("price").lt(300))
                .should(QueryBuilders.termQuery("city","北京"))
        );
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }
//排序和分页
    @Test
    public void SortAndPageTest() throws IOException {
        int page = 1;int size = 5;
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.matchAllQuery());
        searchRequest.source().size(size).from((page-1)*size);
        searchRequest.source().sort("price", SortOrder.ASC);
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

    /**
     * 高亮搜索内容
     * @throws IOException
     */
    @Test
    public void HighlightTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //查询条件
        searchRequest.source().query(QueryBuilders.matchQuery("all","如家酒店"));
        searchRequest.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

对结果相关度算分后重新排序这个稍微复杂点,单独列出来:

/**
     * 根据相关度算分排序
     * @throws IOException
     */
    @Test
    public void functionScoreTest() throws IOException {
        //构建查询request对象
        SearchRequest searchRequest = new SearchRequest("hotel1");
        //基础查询条件
        MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
        //算分查询
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(
                matchAllQuery, //基础查询
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ //算分函数
                    new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                            QueryBuilders.termQuery("isAD",true), //筛选算分条件
                            ScoreFunctionBuilders.weightFactorFunction(10)  //算分方式
                    )
                }).boostMode(CombineFunction.SUM); //对是广告的查询结果加10分
        //查询条件
        searchRequest.source().query(functionScoreQuery);
        //发起查询
        SearchResponse res = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //结果展示
        showRes(res);
    }

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在传统的开发中,我们可能会使用定时任务去实现数据同步的操作,但是这种方案存在一定的不足,例如数据同步的实时性可能不太好;此外,数据条数增多也可能会导致定时任务处理的效率变低。因此,我们可以使用springboot结合eselasticsearch实现数据同步,来解决上述的问题。 首先,我们需要在springboot中引入es的相关依赖,例如spring-boot-starter-data-elasticsearch,这样我们就可以在项目中使用es功能。接着,我们需要定义es的索引,并且定义好与数据库表的映射关系。这里可以使用spring-data-elasticsearch来完成。因为在es中没有表的概念,而是使用索引和类型来代替,因此我们需要将数据库表的数据转换成es中的文档格式。 在实现数据同步的功能时,我们可以使用JPA的监听器,例如@PostPersist,@PostUpdate,@PostRemove等注解,当数据库表的数据发生变化时,监听器会自动触发相应的方法,我们可以在这些方法中编写将数据同步到es的代码逻辑,确保数据同步的实时性。 除了使用监听器来实现数据同步,我们还可以考虑使用消息队列(MQ)的方式,以便将数据同步的逻辑异步执行,降低数据同步时的压力。在MQ应用中,当数据源发生变化时,我们只需要将变化的数据同步到MQ中,之后再使用MQ监听器将数据异步地同步到es中。 总的来说,springboot结合es实现数据同步,能够提升数据同步的实时性和效率,使整个系统更加稳定可靠,适用于数据实时同步场景,同时也为数据分析、搜索等场景提供了更好的支持。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值