相关推荐recommended
Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排
作者:mmseoamin日期:2023-12-14

文章目录

  • ⛄引言
  • 一、我附近的酒店
    • ⛅需求分析
    • ⚡源码编写
    • 二、酒店竞价排名
      • ⌚需求分析
      • ⏰修改搜索业务
      • ✅效果图
      • ⛵小结

        ⛄引言

        本文参考黑马 分布式Elastic search

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

        一、我附近的酒店

        ⛅需求分析

        酒店列表页的右侧,有一个小地图,点击地图的定位按钮,地图会找到你所在的位置:

        Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第1张

        点击定位后,会发送给服务端以下请求json

        Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第2张

        我们要做的事情就是基于这个location坐标,然后按照距离对周围酒店排序。实现思路如下:

        • 修改RequestParams参数,接收location字段
        • 修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能

          ⚡源码编写

          修改实体类

          import lombok.Data;
          @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;
              // 我当前的地理坐标
              private String location;
          }
          

          距离排序

          我们以前学习过排序功能,包括两种:

          • 普通字段排序
          • 地理坐标排序

            地理坐标 DSL 语法如下

            GET /indexName/_search
            {
              "query": {
                "match_all": {}
              },
              "sort": [
                {
                  "price": "asc"  
                },
                {
                  "_geo_distance" : {
                      "FIELD" : "纬度,经度",
                      "order" : "asc",
                      "unit" : "km"
                  }
                }
              ]
            }
            

            添加距离排序

            @Override
            public PageResult search(RequestParams params) {
                try {
                    // 1.准备Request
                    SearchRequest request = new SearchRequest("hotel");
                    // 2.准备DSL
                    // 2.1.query
                    buildBasicQuery(params, request);
                    // 2.2.分页
                    int page = params.getPage();
                    int size = params.getSize();
                    request.source().from((page - 1) * size).size(size);
                    // 2.3.排序
                    String location = params.getLocation();
                    if (location != null && !location.equals("")) {
                        request.source().sort(SortBuilders
                                              .geoDistanceSort("location", new GeoPoint(location))
                                              .order(SortOrder.ASC)
                                              .unit(DistanceUnit.KILOMETERS)
                                             );
                    }
                    // 3.发送请求
                    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
                    // 4.解析响应
                    return handleResponse(response);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            

            排序距离展示

            重启进行测试:

            Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第3张

            的却可以实现 我附近的酒店距离排序,但是没有展示距离我们有多远,这个我们应该怎么实现呢?

            排序完成后,页面还要获取我附近每个酒店的具体距离值,这个值在响应结果中是独立的:

            Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第4张

            因此,我们在结果解析阶段,除了解析source部分以外,还要得到sort部分,也就是排序的距离,然后放到响应结果中。

            我们要做两件事:

            • 修改HotelDoc,添加排序距离字段,用于页面显示
            • 修改HotelService类中的handleResponse方法,添加对sort值的获取

              添加距离排序字段

              import lombok.Data;
              import lombok.NoArgsConstructor;
              @Data
              @NoArgsConstructor
              public class HotelDoc {
                  private Long id;
                  private String name;
                  private String address;
                  private Integer price;
                  private Integer score;
                  private String brand;
                  private String city;
                  private String starName;
                  private String business;
                  private String location;
                  private String pic;
                  // 排序时的 距离值
                  private Object distance;
                  public HotelDoc(Hotel hotel) {
                      this.id = hotel.getId();
                      this.name = hotel.getName();
                      this.address = hotel.getAddress();
                      this.price = hotel.getPrice();
                      this.score = hotel.getScore();
                      this.brand = hotel.getBrand();
                      this.city = hotel.getCity();
                      this.starName = hotel.getStarName();
                      this.business = hotel.getBusiness();
                      this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
                      this.pic = hotel.getPic();
                  }
              }
              

              修改 handleResponse 方法

              Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第5张

              重启进行测试

              Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第6张

              已成功展示距离。

              二、酒店竞价排名

              需求:让指定的酒店在搜索结果中排名置顶

              ⌚需求分析

              要让指定酒店在搜索结果中排名置顶,效果如图:

              Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第7张

              页面会给指定的酒店添加广告标记。

              那怎样才能让指定的酒店排名置顶呢?

              我们之前学习过的function_score查询可以影响算分,算分高了,自然排名也就高了。而function_score包含3个要素:

              • 过滤条件:哪些文档要加分
              • 算分函数:如何计算function score
              • 加权方式:function score 与 query score如何运算

                这里的需求是:让指定酒店排名靠前。因此我们需要给这些酒店添加一个标记,这样在过滤条件中就可以根据这个标记来判断,是否要提高算分。

                比如,我们给酒店添加一个字段:isAD,Boolean类型:

                • true:是广告
                • false:不是广告

                  这样function_score包含3个要素就很好确定了:

                  • 过滤条件:判断isAD 是否为true
                  • 算分函数:我们可以用最简单暴力的weight,固定加权值
                  • 加权方式:可以用默认的相乘,大大提高算分

                    因此,业务的实现步骤包括:

                    1. 给HotelDoc类添加isAD字段,Boolean类型

                    2. 挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true

                    3. 修改search方法,添加function score功能,给isAD值为true的酒店增加权重

                    ⏰修改搜索业务

                    添加广告标记

                    修改实体类

                    import lombok.Data;
                    import lombok.NoArgsConstructor;
                    @Data
                    @NoArgsConstructor
                    public class HotelDoc {
                        private Long id;
                        private String name;
                        private String address;
                        private Integer price;
                        private Integer score;
                        private String brand;
                        private String city;
                        private String starName;
                        private String business;
                        private String location;
                        private String pic;
                        private Object distance;
                        // 加入广告标识
                        private Boolean isAD;
                        public HotelDoc(Hotel hotel) {
                            this.id = hotel.getId();
                            this.name = hotel.getName();
                            this.address = hotel.getAddress();
                            this.price = hotel.getPrice();
                            this.score = hotel.getScore();
                            this.brand = hotel.getBrand();
                            this.city = hotel.getCity();
                            this.starName = hotel.getStarName();
                            this.business = hotel.getBusiness();
                            this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
                            this.pic = hotel.getPic();
                        }
                    }
                    

                    随便设置几个作为广告置项

                    POST /hotel/_update/2056105938
                    {
                        "doc": {
                            "isAD": true
                        }
                    }
                    POST /hotel/_update/38609
                    {
                        "doc": {
                            "isAD": true
                        }
                    }
                    

                    添加算分函数查询

                    接下来我们就要修改查询条件了。之前是用的boolean 查询,现在要改成function_socre查询。

                    function_score查询结构如下:

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第8张

                    对应的JavaAPI如下:

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第9张

                    我们可以将之前写的boolean查询作为原始查询条件放到query中,接下来就是添加过滤条件、算分函数、加权模式了。所以原来的代码依然可以沿用。

                    加入算分查询

                    private void buildBasicQuery(RequestParams params, SearchRequest request) {
                        // 1.构建BooleanQuery
                        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                        // 关键字搜索
                        String key = params.getKey();
                        if (key == null || "".equals(key)) {
                            boolQuery.must(QueryBuilders.matchAllQuery());
                        } else {
                            boolQuery.must(QueryBuilders.matchQuery("all", key));
                        }
                        // 城市条件
                        if (params.getCity() != null && !params.getCity().equals("")) {
                            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
                        }
                        // 品牌条件
                        if (params.getBrand() != null && !params.getBrand().equals("")) {
                            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
                        }
                        // 星级条件
                        if (params.getStarName() != null && !params.getStarName().equals("")) {
                            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
                        }
                        // 价格
                        if (params.getMinPrice() != null && params.getMaxPrice() != null) {
                            boolQuery.filter(QueryBuilders
                                             .rangeQuery("price")
                                             .gte(params.getMinPrice())
                                             .lte(params.getMaxPrice())
                                            );
                        }
                        // 2.算分控制
                        FunctionScoreQueryBuilder functionScoreQuery =
                            QueryBuilders.functionScoreQuery(
                            // 原始查询,相关性算分的查询
                            boolQuery,
                            // function score的数组
                            new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                                // 其中的一个function score 元素
                                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                    // 过滤条件
                                    QueryBuilders.termQuery("isAD", true),
                                    // 算分函数
                                    ScoreFunctionBuilders.weightFactorFunction(10)
                                )
                            });
                        request.source().query(functionScoreQuery);
                    }
                    

                    效果展示

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第10张

                    ✅效果图

                    Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 我附近的、酒店竞排,在这里插入图片描述,第11张

                    ⛵小结

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

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