• 分布式搜索———黑马旅游


    案例功能实现 :

    酒店搜索和分页
    酒店结果过滤
    我周边的酒店
    酒店竞价排名

    资源链接
    hoteld-demo工程:https://pan.baidu.com/s/1YlKz6vxcm7VWXAWPlUiBqg
    提取码:GY66

    进入hoteld-demo工程,启动服务,打开浏览器进入http://localhost:8089/即可成功访问页面
    在这里插入图片描述

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

    1、定义实体类,接收前端请求

    import lombok.Data;
    
    @Data
    public class RequestParams {
        
        // 搜索换关键字
        private String key;     
        // 当前页码
        private Integer page;
        // 分页大小
        private Integer size;
        // 排序字段
        private String sortBy;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    # 返回分页查询结果
    import lombok.Data;
    import java.util.List;
    
    @Data
    public class PageResult {
        private Long total;
        private List<HotelDoc> hotelDocs;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2、定义controller接口,接收页面请求,调用IHotelService的search方法
    ① controller接口

    public interface IHotelService extends IService<Hotel> {
    
        PageResult search(RequestParams params) throws IOException;
    }
    
    • 1
    • 2
    • 3
    • 4

    ② web层

    @RestController
    @RequestMapping("/hotel")
    public class HotelController {
    
        @Autowired
        private IHotelService service;
    
        @PostMapping("/list")
        public PageResult search(@RequestBody RequestParams params) throws IOException {
    
            return  service.search(params);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、定义IHotelService中的search方法,利用match查询实现根据关键字搜索酒店信息

    @Service
    public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
        @Autowired
        private RestHighLevelClient client;
    
        @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)) {
                    request.source().query(QueryBuilders.matchAllQuery());
                } else {
                    request.source().query(QueryBuilders.matchQuery("all", key));
                }
                //  2.2、 分页(利用参数中的page、size实现)
                int page = params.getPage();
                int size = params.getSize();
                request.source().from((page - 1) * size).size(size);
                // 3、发送请求
                SearchResponse response = null;
                response = client.search(request, RequestOptions.DEFAULT);
                //  解析响应
               return handleResonse(response);
    
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        private PageResult handleResonse(SearchResponse response) {
            // 4、解析响应
            SearchHits searchHits = response.getHits();
            long total = searchHits.getTotalHits().value;
            SearchHit[] hits = searchHits.getHits();
            // 遍历
            List<HotelDoc> hotelDocs = new ArrayList<>();
            for (SearchHit hit : hits) {
                String json = hit.getSourceAsString();
                // 反序列化
                HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
                hotelDocs.add(hotelDoc);
            }
                // 封装返回
                return new PageResult(total,hotelDocs);
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    启动服务,进行测试
    在这里插入图片描述

    案例二: 添加品牌、城市、星级、价格等过滤功能

    1、修改RequestParams类(前端所传的数据),添加brand、city、starName、minPrice、maxPrice等参数

    package com.GY.hotel.pojo;
    
    import lombok.Data;
    @Data
    public class RequestParams {
    
        // 搜索换关键字
        private String key;
        // 当前页码
        private Integer page;
        // 分页大小
        private Integer size;
        // 排序字段
        private String sortBy;
        // 品牌
        private String brand;
        // 城市
        private String city;
        // 星级
        private  String starName;
        // 最低价格
        private int minPrice;
        // 最高价格
        private int maxPrice;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2、修改search方法的实现,在match查询基础上添加过滤条件,在关键字搜索时,在如果brand等参数存在,对其做过滤

    过滤条件包括:
    ●  city精确匹配  (term查询)
    ●  brand精确匹配   (term查询)
    ●  starName精确匹配    (term查询)
    ●  price范围过滤     (range查询)
    注意事项:
    ●  多个条件之间是AND关系,组合多条件用BooleanQuery
    ●  参数存在才需要过滤,做好非空判断
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Service
    public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    
        @Autowired
        private RestHighLevelClient client;
    
        @Override
        public PageResult search(RequestParams params) {
            // 查询分页
            try {
                // 1、创建request对象
                SearchRequest request = new SearchRequest("hotel");
                // 2、准备DSL
                //  2.1、 query
                    // 构建BooleanQuery
                buildBasicQuery(params, request);
                //  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);
                //  解析响应
               return handleResponse(response);
    
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    
        private void buildBasicQuery(RequestParams params, SearchRequest request) {
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            // 关键字搜索
            String key = params.getKey();
            if (key == null || "".equals(key)) {
                boolQuery.must(QueryBuilders.matchAllQuery());
            } else {
                boolQuery.must(QueryBuilders.matchQuery("name", key));
            }
            // 城市条件 (term属于过滤条件放在must中会影响得分进而影响查询性能)
            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()));
            }
            request.source().query(boolQuery);
        }
    
        private PageResult handleResponse(SearchResponse response) {
            // 4、解析响应
            SearchHits searchHits = response.getHits();
            long total = searchHits.getTotalHits().value;
            SearchHit[] hits = searchHits.getHits();
            // 遍历
            List<HotelDoc> hotels = new ArrayList<>();
            for (SearchHit hit : hits) {
                String json = hit.getSourceAsString();
                // 反序列化
                HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
                hotels.add(hotelDoc);
            }
                // 封装返回
                return new PageResult(total,hotels);
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    重新启动服务进行测试(过滤成功!!!
    在这里插入图片描述

    案例三: 我附近的酒店
    前端页面点击定位后,会将你所在的位置发送到后台。我们要根据这个坐标,将酒店结果按照到这个点的距离升序排序。

    在这里插入图片描述
    1、修改RequestParams参数,接收location字段

    // 位置
        private String location;
    
    • 1
    • 2

    2、修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能

    //  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));
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    按照距离排序后,还需要显示具体的距离值:
    ① HotelDoc实体类中添加distance属性
    在这里插入图片描述

    ② 修改结果解析响应

    private PageResult handleResponse(SearchResponse response) {
            // 4、解析响应
            SearchHits searchHits = response.getHits();
            long total = searchHits.getTotalHits().value;
            SearchHit[] hits = searchHits.getHits();
            // 遍历
            List<HotelDoc> hotels = new ArrayList<>();
            for (SearchHit hit : hits) {
                String json = hit.getSourceAsString();
                // 反序列化
                HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
                // 获取排序值
                Object[] sortValues = hit.getSortValues();
                if (sortValues.length>0){
                    Object value = sortValues[0];
                    hotelDoc.setDistance(value);
                }
                hotels.add(hotelDoc);
            }
                // 封装返回
                return new PageResult(total,hotels);
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    重新启动服务进行测试(成功显示数据且排序成功!!!
    在这里插入图片描述

    案例四:让指定的酒店在搜索结果中排名置顶
    给需要置顶的酒店文档添加一个标记。然后利用function score给带有标记的文档增加权重。效果如下所示:
    在这里插入图片描述

    1、给HotelDoc类添加isAD字段,Boolean类型
    在这里插入图片描述

    2、挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
    在这里插入图片描述

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

    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("name", key));
        }
        // 城市条件 (term属于过滤条件放在must中会影响得分进而影响查询性能)
        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),
                                            // 算分函数(分值*10)
                                            ScoreFunctionBuilders.weightFactorFunction(10)
                                )
                        });
        request.source().query(functionScoreQuery);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    广告置顶成功
    在这里插入图片描述

  • 相关阅读:
    Miniconda 安装和使用笔记
    用HTML+CSS做一个漂亮简单的个人网页——动漫网页【火影忍者】1个页面
    pytorch初学笔记(一):如何加载数据和Dataset实战
    Unity中的MVC思想
    ORM数据库操作
    Python游戏篇:细节之大型游戏爆炸效果(附代码)
    NFT 交易市场的后起之秀要如何超越 OpenSea?
    免费小程序商城搭建之b2b2c o2o 多商家入驻商城 直播带货商城 电子商务b2b2c o2o 多商家入驻商城 直播带货商城 电子商务
    简单了解ARP协议
    react 18新特性 了解一下
  • 原文地址:https://blog.csdn.net/m0_56188609/article/details/127685879