Spring Boot集成Elasticsearch复杂查询

前言

项目中经常会遇到一些比较复杂的查询,如何使用RestHighLevelClient来实现查询呢,本文将讲解Spring Boot采用RestHighLevelClient如何实现高级查询。
 

数据准备 

我们准备相关的数据来展示相关的示例。

具体实现

分页组合查询

分页查询:采用from、size的方式进行分页和Mysql的limit分页原理是一样的,from代表是数据从那条开始,size代表是查询多少条数据。

Controller实现

@GetMapping("/pageSearch")
    public Result pageSearch(String indexName,String key,String value) throws IOException 
    {
        //设置多个文档
        SearchRequest request =new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
        //表示从什么位置开始,查询多少条数据
        sourceBuilder.from(0).size(2);
        //按照价格排序
        sourceBuilder.sort("price",SortOrder.DESC);
        request.source(sourceBuilder);
        SearchResponse response =client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : hits) 
        {
            logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
        }
        return Result.success(searchHits);
    }

输出结果

c.s.f.e.c.RestHightController - search Id:12,hit data:{"createDate":1655132070891,"id":"12","price":110.0,"skuNo":"sku0012","title":"java设计模式"}c.s.f.e.c.RestHightController - search Id:10,hit data:{"createDate":1655132070891,"id":"10","price":105.0,"skuNo":"sku0011","title":"Effive java"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO  [] c.s.f.e.c.RestHightController - search Id:11,hit data:{"createDate":1655132070891,"id":"11","price":100.0,"skuNo":"sku0011","title":"java架构设计"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO  [] c.s.f.e.c.RestHightController - search Id:2,hit data:{"createDate":1655132070891,"id":"2","price":99.0,"skuNo":"sku0002","title":"java从入门到精通"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO  [] c.s.f.e.c.RestHightController - search Id:3,hit data:{"createDate":1655132070891,"id":"3","price":89.0,"skuNo":"sku0003","title":"java编程思想"}

说明:从输出结果可以看出,通过查询包含java的数据,分页显示5条数据,且按照价格进行排序。

分组查询

分组查询:采用TermAggregation针对某个字段进行分组查询。

Controller实现

 @GetMapping("/aggSearch")
    public Result aggSearch(String indexName,String key,String value) throws IOException 
    {
        SearchRequest request =new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
        //按照价格进行聚合
        AggregationBuilder ageAgg = AggregationBuilders.terms("priceGroup").field("price").size(10);
        sourceBuilder.aggregation(ageAgg);
        request.source(sourceBuilder);
        SearchResponse response =client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : hits) 
        {
            logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
        }
        Aggregations aggregations = response.getAggregations();
        //数据为double类型,采用ParsedDoubleTerms
        ParsedDoubleTerms parsedDoubleTerms = aggregations.get("priceGroup");
        // 输出匹配的结果数据
        List<? extends Terms.Bucket> buckets = parsedDoubleTerms.getBuckets();
        for (Terms.Bucket bucket:buckets)
        {
           logger.info("key:{},count:{}",bucket.getKeyAsString(),bucket.getDocCount());
        }
        return Result.success(searchHits);
    }

说明:针对price字段进行分组查询,如果是double类型的数据,需要采用ParsedDoubleTerms进行接收,否则会报类型转换错误。

输出结果

c.s.f.e.c.RestHightController - key:89.0,count:2
c.s.f.e.c.RestHightController - key:99.0,count:1
c.s.f.e.c.RestHightController - key:100.0,count:1
c.s.f.e.c.RestHightController - key:105.0,count:1
c.s.f.e.c.RestHightController - key:110.0,count:1

聚合查询

聚合查询通常包含:Max、Min、AVG、Sum等查询

Controller实现

 /**
     * 聚合查询
     * @param indexName
     * @param key
     * @param value
     * @return
     * @throws IOException
     */
    @GetMapping("/sumSearch")
    public Result sumSearch(String indexName,String type,String key,String value) throws IOException 
    {
        //设置多个文档
        SearchRequest request =new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
        AggregationBuilder ageAgg  =null;
        //按照条件进行聚合
        if("max".equals(type))
        {
            ageAgg=AggregationBuilders.max("priceMax").field("price");
        }
        else if("min".equals(type))
        {
            ageAgg=AggregationBuilders.min("priceMin").field("price");
        }
        else if("avg".equals(type))
        {
            ageAgg=AggregationBuilders.avg("priceAvg").field("price");
        }
        else
        {
          ageAgg= AggregationBuilders.sum("priceSum").field("price");
        }
              
        sourceBuilder.aggregation(ageAgg);
        request.source(sourceBuilder);
        SearchResponse response =client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : hits) 
        {
            logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
        }
        
        Aggregations aggregations = response.getAggregations();
        //价格之和
        /**
         max 使用ParsedMax处理
         min 使用ParsedMin处理
         avg 使用 ParsedAvg处理
         sum 使用ParsedSum处理
        */
        if("max".equals(type))
        {
            ParsedMax preMax = aggregations.get("priceMax");
            logger.info("求最大为:"+preMax.value());
        }
        else if("min".equals(type))
        {
            ParsedMin preMin = aggregations.get("priceMin");
            logger.info("求最小为:"+preMin.value());
        }
        else if("avg".equals(type))
        {
            ParsedAvg preAvg = aggregations.get("priceAvg");
            logger.info("求平均值为:"+preAvg.value());
        }
        else
        {
           ParsedSum parsedSum = aggregations.get("priceSum");
           logger.info("求和值为:"+parsedSum.value());
        }
        return Result.success(searchHits);
    }

说明:

  • Type:类型:通过传入不同的值,进行不同的聚合查询,
  • ParsedSum :处理求和后的结果
  • ParsedAvg :处理求平均值的结果
  • ParsedMin :处理最小值的结果
  • ParsedMax:处理最大值的结果

输出结果

例如求平均值:

2022-06-14 22:28:52.938 [http-nio-9090-exec-6] INFO  [] c.s.f.e.c.RestHightController - 求平均值为:98.66666666666667

Top查询

Controller实现

 @GetMapping("/topSearch")
    public Result topSearch(String indexName,String key,String value) throws IOException 
    {
        SearchRequest request =new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
        //按照价格排序获取前2条
        AggregationBuilder aggregationBuilder = AggregationBuilders.topHits("price_top").sort(SortBuilders.fieldSort("price").order(SortOrder.DESC)).size(2);
        sourceBuilder.aggregation(aggregationBuilder);
        request.source(sourceBuilder);
        SearchResponse response =client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : hits) 
        {
            logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
        }
        //输出结果
        Aggregations aggregations = response.getAggregations();
        TopHits topHits = aggregations.get("price_top");
        SearchHits hitsRes = topHits.getHits();
        for (SearchHit hit : hitsRes.getHits())
        {
            logger.info("id:{} ,Top data:{}",hit.getId(),hit.getSourceAsString());
        }
        return Result.success(searchHits);
    }

说明:通过price进行排序获取前2条记录。

输出结果

c.s.f.e.c.RestHightController - id:12 ,Top data:{"createDate":1655132070891,"id":"12","price":110.0,"skuNo":"sku0012","title":"java设计模式"}
c.s.f.e.c.RestHightController - id:10 ,Top data:{"createDate":1655132070891,"id":"10","price":105.0,"skuNo":"sku0010","title":"Effive java"}

高亮显示

Controller实现

 @GetMapping("/hightSearch")
    public Result hightSearch(String indexName,String key,String value) throws IOException 
    {
        SearchRequest request =new SearchRequest(indexName);
        //构造查询条件
        SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
        //设置高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>");
        highlightBuilder.highlighterType("unified"); // 设置字段高光色类型。
        highlightBuilder.field("title").field("remark");   //将字段高光色添加到高亮构建器。
        //设置值
        sourceBuilder.highlighter(highlightBuilder);
        request.source(sourceBuilder);
        SearchResponse response =client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit: searchHits)
        {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
           if(highlightFields.containsKey("remark"))
           {
               logger.info("remark高亮的结果:{}",highlightFields.get("remark").fragments()[0]);
           }
           
            if(highlightFields.containsKey("title"))
            {
                logger.info("title高亮的结果:{}",highlightFields.get("title").fragments()[0]);
            }
        }
        return Result.success(searchHits);
    }

说明:通过查询包含java的标题显示为红色。

输出结果

c.s.f.e.c.RestHightController - title高亮的结果:<span style='color:red'>java</span>架构设计
c.s.f.e.c.RestHightController - title高亮的结果:<span style='color:red'>java</span>从入门到精通

总结

本文重点讲解了Spring Boot集成Elasticsearch实现一些复杂的查询,如有疑问可以随时反馈。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是一个简单的 Spring Boot 集成 Elasticsearch 的示例: 1. 添加 Elasticsearch 依赖 在 `pom.xml` 文件中添加 Elasticsearch 的 Maven 依赖: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> </dependencies> ``` 2. 配置 Elasticsearch 在 `application.properties` 中添加 Elasticsearch 的配置信息: ```properties # Elasticsearch 配置 spring.data.elasticsearch.cluster-name=my-application spring.data.elasticsearch.cluster-nodes=localhost:9300 ``` 3. 创建实体类 创建一个实体类,用于映射 Elasticsearch 中的一个文档: ```java import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; @Document(indexName = "books") public class Book { @Id private String id; private String title; private String author; // getter 和 setter 略 } ``` 4. 创建 Elasticsearch Repository 创建一个 Elasticsearch Repository,用于操作 Elasticsearch 中的文档: ```java import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; public interface BookRepository extends ElasticsearchRepository<Book, String> {} ``` 5. 使用 Elasticsearch Repository 在需要使用 Elasticsearch 的地方,注入 `BookRepository`,然后就可以对 Elasticsearch 中的文档进行操作了: ```java @Autowired private BookRepository bookRepository; public void addBook(Book book) { bookRepository.save(book); } public List<Book> searchBooks(String keyword) { return bookRepository.findByTitleContainingOrAuthorContaining(keyword, keyword); } public void deleteBook(String id) { bookRepository.deleteById(id); } ``` 以上就是一个简单的 Spring Boot 集成 Elasticsearch 的示例。当然,在实际使用中,还需要更多的配置和代码来支持更多的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值