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

news2024/11/28 12:51:30

案例功能实现 :

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

资源链接
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;
}
# 返回分页查询结果
import lombok.Data;
import java.util.List;

@Data
public class PageResult {
    private Long total;
    private List<HotelDoc> hotelDocs;
}

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

public interface IHotelService extends IService<Hotel> {

    PageResult search(RequestParams params) throws IOException;
}

② 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);
    }
}

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、修改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;
}

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

过滤条件包括:
●  city精确匹配  (term查询)
●  brand精确匹配   (term查询)
●  starName精确匹配    (term查询)
●  price范围过滤     (range查询)
注意事项:
●  多个条件之间是AND关系,组合多条件用BooleanQuery
●  参数存在才需要过滤,做好非空判断
@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、修改RequestParams参数,接收location字段

// 位置
    private String location;

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));
            }

按照距离排序后,还需要显示具体的距离值:
① 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);
        }
}

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

案例四:让指定的酒店在搜索结果中排名置顶
给需要置顶的酒店文档添加一个标记。然后利用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);
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp微信小程序半屏跳转小程序

1、资料设置申请绑定 进入微信小程序 设置 -> 第三方设置 -> 半屏小程序管理 添加需要绑定的小程序的appid 等待审核&#xff0c;审核通过后开始写代码 2、代码编写 &#xff08;1&#xff09;、以前的跳转方式是uni.navigateToMiniProgram 换成wx.openEmbeddedMiniP…

Spring核心思想

文章目录1. Spring核心思想1.1 Spring是什么1.2 什么是容器1.3 什么是loC1.3.1 传统开发1.3.2 如何解决传统开发中耦合度高的问题1.3.3 控制反转程序的编写1.4 理解Spring loC1.5 什么是DI1. Spring核心思想 1.1 Spring是什么 我们通常说的Spring是Spring Framework(Spring框…

一个非常实用的分布式 JVM 监控工具

介绍 该项目为了方便开发者更快监控多个远程主机jvm&#xff0c;如果你的项目是Spring boot那么很方便集成&#xff0c;jar包引入即可&#xff0c;不是Spring boot也不用气馁&#xff0c;你可以快速自行初始化一个Spirng boot程序引入jar包即可 效果展示 整体架构 git地址 ht…

Kafka由浅入深(6) Sender线程执行源码解析

一、KafkaProducer消息流程图 1.1 KafkaProducer 消息架构图 1.2 KafkaProducer 消息架构分为两部分 第一部分是KafkaProducer主线程 主要逻辑提供消息拦截器、序列化器、和分区器的默认实现和对外自定义扩展功能&#xff0c;已经将消息追加并缓存到累加器RecordAccumulator…

NeurIPS 2022 | 涨点神器!利用图像辅助三维点云分析的训练新范式

原文链接&#xff1a;https://www.techbeat.net/article-info?id4212 作者&#xff1a;颜旭 点云作为一种基本的三维表征形式&#xff0c;活跃在自动驾驶、机器人感知等多种任务上。尽管三维点云分析在近年来取得了良好的发展&#xff0c;但由于点云其本身往往是无序、无纹理以…

OpenCV笔记--人脸识别算法Eigenfaces和Fisherfaces

目录 1--前言 2--处理ORL数据集 3--Eigenfaces复现过程 4--Fisherfaces复现过程 5--分析 1--前言 ①SYSU模式识别课程作业 ②配置&#xff1a;基于Windows11、OpenCV4.5.5、VSCode、CMake&#xff08;参考OpenCV配置方式&#xff09; ③原理及源码介绍&#xff1a;Face…

云栖探馆!云小宝首秀遇上老司机小龙,猜猜谁赢了?

为啥人人都喜欢秋天呢&#xff1f;因为我们打喷嚏都是“爱秋”啊&#xff5e; 为啥大家会来云栖大会呢&#xff1f;因为云栖大会让我们在一“栖”啊&#xff5e; 2022云栖大会龙蜥峰会&#xff0c;小龙来啦~&#xff01; ​ 去年&#xff0c;小龙作为萌新来到云栖大会&#…

归并排序.

归并排序介绍 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用金典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各个答案"修补"在一起,即分而治之) 归并排序的思想示…

为什么程序员会秃头?盘点程序员糟心的几大因素

程序员与脱发似乎存在某种必然的逻辑连接&#xff0c;程序员秃头已经成为大家心中的思维定势。 一提到程序员&#xff0c;难免会想起来java&#xff0c; c&#xff0c; python以及无休止的debug环节&#xff0c;不难想象经常会有程序员跳楼自杀的情况。因为实在是生存不易&…

L5W1作业1 手把手实现循环神经网络

欢迎来到课程5的第一个作业&#xff01;在此作业中&#xff0c;你将使用numpy实现你的第一个循环神经网络。 循环神经网络&#xff08;RNN&#xff09;在解决自然语言处理和其他序列任务上非常有效&#xff0c;因为它们具有“记忆”&#xff0c;可以一次读取一个输入 x⟨t⟩x^…

C语言百日刷题第六天

C语言百日刷题第六天51.鸡兔同笼问题52.输出所有形如aabb的完全平方数53.3n1问题54.输出100~999的所有水仙花数55.韩信点兵56.倒三角形57.求子序列的和58.分数化小数59.开灯问题60.蛇形填数51.鸡兔同笼问题 分析&#xff1a;小学生数学问题。设鸡为a个&#xff0c;兔为b个&…

大数据技术基础实验十:Hive实验——新建Hive表

大数据技术基础实验十&#xff1a;Hive实验——新建Hive表 文章目录大数据技术基础实验十&#xff1a;Hive实验——新建Hive表一、前言二、实验目的三、实验要求四、实验原理五、实验步骤1、启动Hive2、创建表3、显示表4、显示表列5、更改表6、删除表或者列六、最后我想说一、前…

vue学习笔记——简单入门总结(三)

文章目录1.Vue的理解&#xff1a;1.1.mvvm模型&#xff1a;1.2.vue2的数据代理&#xff1a;1.3.vue2的生命周期&#xff1a;1.4.vue中的render函数&#xff1a;1.5. mixin混入&#xff1a;2.Vue组件间通信&#xff1a;2.0.props&#xff1a;2.1.全局事件总线&#xff1a;2.2.消…

WeMos Mini ESP32-S2FN4R2介绍

WeMos Mini ESP32-S2FN4R2介绍LOLIN S2 Mini V1.0.0 ESP32-S2 4MB FLASH 2MB PSRAM WIFI开发板 &#x1f33c;功能介绍 基于 ESP32-S2FN4R2TYPE-C USB27个数字输入/输出引脚&#xff0c;所有引脚都支持中断/pwm/I2C/单线ADC、DAC、I2C、SPI、UART、USB OTG &#x1f4cd; 详细…

棋盘(马蹄集)

棋盘 难度&#xff1a;白银 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 求一个N*N棋盘中的方块总数。 格式 输入格式&#xff1a;输入整型N 输出格式&#xff1a;输出整型 CSDN盛溪的猫 #include<bits/stdc.h> using namespace std; int main(){ long n,sum1;…

Mybatis要点总结

一、了解orm框架 1.什么是ORM框架&#xff1a;对象关系映射&#xff08;Object Relational Mapping&#xff0c;简称ORM&#xff09;&#xff0c;该模式是为了解决面向对象与关系数据库互补匹配的现象的技术&#xff1b;orm框架是连接数据库的桥梁&#xff0c;主要提供了人持久…

大数据技术之Zookeeper总结Ⅰ

zookeeper总结目录1. Zookeeper 入门1.1 zookeeper概述1.2 Zookeeper特点1.3 ZooKeeper 数据模型的结构2. Zookeeper 本地安装2.1 本地模式安装2.2 配置参数解读3. Zookeeper 集群操作3.1 集群操作3.2 Zookeeper 集群启动停止脚本3.3 客户端命令行语法1. Zookeeper 入门 1.1 z…

数据结构七:七大排序

目录 1&#xff1a;排序的概率 2.插入排序 2.1&#xff1a;直接插入排序-----稳定 2.1.1&#xff1a;基本思想 2.2&#xff1a;希尔排序 2.2.1&#xff1a;概念&#xff1a; 3.选择排序 3.1&#xff1a;选择排序 3.1.1&#xff1a;概念 3.2:堆排序 4.交换排序 4.1&…

微信小程序自动化测试之路

1. 前言 在每次发布新版本之前、都需要回归核心功能、已确保上线后小程序也能按照预期运行. 目前这部分回归工作是由测试同事手工去验证测试用例、按照每周一版本的迭代节奏、回归就花了测试挺多时间的. 最近前端工作比较轻松、故在思考能否把这部分重复的工作交给程序自动来进…

【EhCache: 一款Java的进程内缓存框架】EhCache 是什么、代码实战 Demo

文章目录1 EhCache 是什么2 代码实战 DemoTestEH.javaehcache.xml1 EhCache 是什么 Ehcache 是一种开源的、基于标准的缓存&#xff0c;可提高性能、卸载数据库并简化可扩展性。它是最广泛使用的基于 Java 的缓存&#xff0c;因为它健壮、经过验证、功能齐全&#xff0c;并且与…