Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤
作者:mmseoamin日期:2023-12-18

文章目录

  • ⛄引言
  • 一、酒店搜索和分页
    • ⛅需求分析
    • ⚡源码编写
    • 二、酒店结果过滤
      • ⌚需求分析
      • ⏰修改搜索业务
      • ✅效果图
      • ⛵小结

        ⛄引言

        本文参考黑马 分布式Elastic search

        Elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容

        一、酒店搜索和分页

        ⛅需求分析

        实现黑马旅游的酒店搜索功能,完成关键字搜索和分页

        在项目首页,有一个很大的搜索框、也有分页按钮

        Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第1张

        点击搜索按钮,可以看到浏览器控制台 网络发出了请求

        Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第2张

        请求参数如下:

        {
            "key": "",
            "page": 1,
            "size": 5,
            "sortBy": "default"
        }
        

        由此可以知道,我们这个请求的信息如下:

        • 请求方式:POST
        • 请求路径:/hotel/list
        • 请求参数:JSON对象,包含4个字段:
          • key:搜索关键字
          • page:页码
          • size:每页大小
          • sortBy:排序,目前暂不实现
          • 返回值:分页查询,需要返回分页结果PageResult,包含两个属性:
            • total:总条数
            • List:当前页的数据

              因此,我们实现业务的流程如下:

              • 步骤一:定义实体类,接收请求参数的JSON对象
              • 步骤二:编写controller,接收页面的请求
              • 步骤三:编写业务实现,利用RestHighLevelClient实现搜索、分页

                ⚡源码编写

                定义实体类

                实体类有两个,一个是前端的请求参数实体,一个是服务端应该返回的响应结果实体。

                import lombok.Data;
                @Data
                public class RequestParams {
                    private String key;
                    private Integer page;
                    private Integer size;
                    private String sortBy;
                }
                

                定义返回值对象,由于要实现分页,所以需要定义。

                import lombok.Data;
                import java.util.List;
                @Data
                public class PageResult {
                    private Long total;
                    private List hotels;
                    public PageResult() {
                    }
                    public PageResult(Long total, List hotels) {
                        this.total = total;
                        this.hotels = hotels;
                    }
                }
                

                定义Controller 控制层

                定义一个HotelController,声明查询接口,满足下列要求:

                • 请求方式:Post
                • 请求路径:/hotel/list
                • 请求参数:对象,类型为RequestParam
                • 返回值:PageResult,包含两个属性
                  • Long total:总条数
                  • List hotels:酒店数据
                    @RestController
                    @RequestMapping("/hotel")
                    public class HotelController {
                        @Autowired
                        private IHotelService hotelService;
                    	// 搜索酒店数据
                        @PostMapping("/list")
                        public PageResult search(@RequestBody RequestParams params){
                            return hotelService.search(params);
                        }
                    }
                    

                    实现搜索业务

                    我们在controller调用了IHotelService,并没有实现该方法,因此下面我们就在IHotelService中定义方法,并且去实现业务逻辑。

                    1)在cn.itcast.hotel.service中的IHotelService接口中定义一个方法:

                    /**
                     * 根据关键字搜索酒店信息
                     * @param params 请求参数对象,包含用户输入的关键字 
                     * @return 酒店文档列表
                     */
                    PageResult search(RequestParams params);
                    

                    2)实现搜索业务,肯定离不开RestHighLevelClient,我们需要把它注册到Spring中作为一个Bean。在项目中的HotelDemoApplication中声明这个Bean:

                    @Bean
                    public RestHighLevelClient client(){
                        return  new RestHighLevelClient(RestClient.builder(
                            HttpHost.create("http://IP地址:9200")
                        ));
                    }
                    

                    3)在service.impl中的HotelService中实现search方法:

                    @Override
                    public PageResult search(RequestParams params) {
                        try {
                            // 1.准备Request
                            SearchRequest request = new SearchRequest("hotel");
                            // 2.准备DSL
                            // 2.1.query
                            String key = params.getKey();
                            if (key == null || "".equals(key)) {
                                boolQuery.must(QueryBuilders.matchAllQuery());
                            } else {
                                boolQuery.must(QueryBuilders.matchQuery("all", key));
                            }
                            // 2.2.分页
                            int page = params.getPage();
                            int size = params.getSize();
                            request.source().from((page - 1) * size).size(size);
                            // 3.发送请求
                            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
                            // 4.解析响应
                            return handleResponse(response);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    // 结果解析
                    private PageResult handleResponse(SearchResponse response) {
                        // 4.解析响应
                        SearchHits searchHits = response.getHits();
                        // 4.1.获取总条数
                        long total = searchHits.getTotalHits().value;
                        // 4.2.文档数组
                        SearchHit[] hits = searchHits.getHits();
                        // 4.3.遍历
                        List hotels = new ArrayList<>();
                        for (SearchHit hit : hits) {
                            // 获取文档source
                            String json = hit.getSourceAsString();
                            // 反序列化
                            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
                    		// 放入集合
                            hotels.add(hotelDoc);
                        }
                        // 4.4.封装返回
                        return new PageResult(total, hotels);
                    }
                    

                    二、酒店结果过滤

                    ⌚需求分析

                    需求: 添加品牌、城市、星级、价格等过滤功能

                    在页面搜索框下,会有几个过滤条件

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第3张

                    请求参数如下:

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第4张

                    包含的过滤条件有:

                    • brand:品牌值
                    • city:城市
                    • minPrice~maxPrice:价格范围
                    • starName:星级

                      我们需要做两件事情:

                      • 修改请求参数的对象RequestParams,接收上述参数
                      • 修改业务逻辑,在搜索条件之外,添加一些过滤条件

                        修改实体类

                        @Data
                        public class RequestParams {
                            private String key;
                            private Integer page;
                            private Integer size;
                            private String sortBy;
                            // 下面是新增的过滤条件参数
                            private String city;
                            private String brand;
                            private String starName;
                            private Integer minPrice;
                            private Integer maxPrice;
                        }
                        

                        ⏰修改搜索业务

                        在HotelService的search方法中,只有一个地方需要修改:requet.source().query( … )其中的查询条件。

                        在之前的业务中,只有match查询,根据关键字搜索,现在要添加条件过滤,包括:

                        • 品牌过滤:是keyword类型,用term查询
                        • 星级过滤:是keyword类型,用term查询
                        • 价格过滤:是数值类型,用range查询
                        • 城市过滤:是keyword类型,用term查询

                          多个查询条件组合,肯定是boolean查询来组合:

                          • 关键字搜索放到must中,参与算分
                          • 其它过滤条件放到filter中,不参与算分

                            因为条件构建的逻辑比较复杂,这里先封装为一个函数:

                            Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第5张

                            buildBasicQuery 函数如下:

                            private void buildBasicQuery(RequestParams params, SearchRequest request) {
                                // 1.构建BooleanQuery
                                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                                // 2.关键字搜索
                                String key = params.getKey();
                                if (key == null || "".equals(key)) {
                                    boolQuery.must(QueryBuilders.matchAllQuery());
                                } else {
                                    boolQuery.must(QueryBuilders.matchQuery("all", key));
                                }
                                // 3.城市条件
                                if (params.getCity() != null && !params.getCity().equals("")) {
                                    boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
                                }
                                // 4.品牌条件
                                if (params.getBrand() != null && !params.getBrand().equals("")) {
                                    boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
                                }
                                // 5.星级条件
                                if (params.getStarName() != null && !params.getStarName().equals("")) {
                                    boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
                                }
                            	// 6.价格
                                if (params.getMinPrice() != null && params.getMaxPrice() != null) {
                                    boolQuery.filter(QueryBuilders
                                                     .rangeQuery("price")
                                                     .gte(params.getMinPrice())
                                                     .lte(params.getMaxPrice())
                                                    );
                                }
                            	// 7.放入source
                                request.source().query(boolQuery);
                            }
                            

                            再次重启运行即可。

                            ✅效果图

                            Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤,在这里插入图片描述,第6张

                            ⛵小结

                            以上就是【Bug 终结者】对 Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤 的简单介绍,ES搜索引擎无疑是最优秀的分布式搜索引擎,使用它,可大大提高项目的灵活、高效性! 技术改变世界!!!

                            如果这篇【文章】有帮助到你,希望可以给【Bug 终结者】点个赞👍,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【Bug 终结者】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💝💝💝!