文章目录
⛄引言
本文参考黑马 分布式Elastic search
Elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容
一、我附近的酒店
⛅需求分析
在酒店列表页的右侧,有一个小地图,点击地图的定位按钮,地图会找到你所在的位置:
点击定位后,会发送给服务端以下请求json
我们要做的事情就是基于这个location坐标,然后按照距离对周围酒店排序。实现思路如下:
- 修改RequestParams参数,接收location字段
- 修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能
⚡源码编写
修改实体类
importlombok.Data;@DatapublicclassRequestParams{privateString key;privateInteger page;privateInteger size;privateString sortBy;privateString city;privateString brand;privateString starName;privateInteger minPrice;privateInteger maxPrice;// 我当前的地理坐标privateString location;}
距离排序
我们以前学习过排序功能,包括两种:
- 普通字段排序
- 地理坐标排序
地理坐标 DSL 语法如下
GET/indexName/_search
{"query":{"match_all":{}},"sort":[{"price":"asc"},{"_geo_distance":{"FIELD":"纬度,经度","order":"asc","unit":"km"}}]}
添加距离排序
@OverridepublicPageResultsearch(RequestParams params){try{// 1.准备RequestSearchRequest request =newSearchRequest("hotel");// 2.准备DSL// 2.1.querybuildBasicQuery(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",newGeoPoint(location)).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS));}// 3.发送请求SearchResponse response = client.search(request,RequestOptions.DEFAULT);// 4.解析响应returnhandleResponse(response);}catch(IOException e){thrownewRuntimeException(e);}}
排序距离展示
重启进行测试:
的却可以实现 我附近的酒店距离排序,但是没有展示距离我们有多远,这个我们应该怎么实现呢?
排序完成后,页面还要获取我附近每个酒店的具体距离值,这个值在响应结果中是独立的:
因此,我们在结果解析阶段,除了解析source部分以外,还要得到sort部分,也就是排序的距离,然后放到响应结果中。
我们要做两件事:
- 修改HotelDoc,添加排序距离字段,用于页面显示
- 修改HotelService类中的handleResponse方法,添加对sort值的获取
添加距离排序字段
importlombok.Data;importlombok.NoArgsConstructor;@Data@NoArgsConstructorpublicclassHotelDoc{privateLong id;privateString name;privateString address;privateInteger price;privateInteger score;privateString brand;privateString city;privateString starName;privateString business;privateString location;privateString pic;// 排序时的 距离值privateObject distance;publicHotelDoc(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 方法
重启进行测试
已成功展示距离。
二、酒店竞价排名
需求:让指定的酒店在搜索结果中排名置顶
⌚需求分析
要让指定酒店在搜索结果中排名置顶,效果如图:
页面会给指定的酒店添加广告标记。
那怎样才能让指定的酒店排名置顶呢?
我们之前学习过的function_score查询可以影响算分,算分高了,自然排名也就高了。而function_score包含3个要素:
- 过滤条件:哪些文档要加分
- 算分函数:如何计算function score
- 加权方式:function score 与 query score如何运算
这里的需求是:让指定酒店排名靠前。因此我们需要给这些酒店添加一个标记,这样在过滤条件中就可以根据这个标记来判断,是否要提高算分。
比如,我们给酒店添加一个字段:isAD,Boolean类型:
- true:是广告
- false:不是广告
这样function_score包含3个要素就很好确定了:
- 过滤条件:判断isAD 是否为true
- 算分函数:我们可以用最简单暴力的weight,固定加权值
- 加权方式:可以用默认的相乘,大大提高算分
因此,业务的实现步骤包括:
- 给HotelDoc类添加isAD字段,Boolean类型
- 挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
- 修改search方法,添加function score功能,给isAD值为true的酒店增加权重
⏰修改搜索业务
添加广告标记
修改实体类
importlombok.Data;importlombok.NoArgsConstructor;@Data@NoArgsConstructorpublicclassHotelDoc{privateLong id;privateString name;privateString address;privateInteger price;privateInteger score;privateString brand;privateString city;privateString starName;privateString business;privateString location;privateString pic;privateObject distance;// 加入广告标识privateBoolean isAD;publicHotelDoc(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查询结构如下:
对应的JavaAPI如下:
我们可以将之前写的boolean查询作为原始查询条件放到query中,接下来就是添加过滤条件、算分函数、加权模式了。所以原来的代码依然可以沿用。
加入算分查询
privatevoidbuildBasicQuery(RequestParams params,SearchRequest request){// 1.构建BooleanQueryBoolQueryBuilder 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的数组newFunctionScoreQueryBuilder.FilterFunctionBuilder[]{// 其中的一个function score 元素newFunctionScoreQueryBuilder.FilterFunctionBuilder(// 过滤条件QueryBuilders.termQuery("isAD",true),// 算分函数ScoreFunctionBuilders.weightFactorFunction(10))});
request.source().query(functionScoreQuery);}
效果展示
✅效果图
⛵小结
以上就是【Bug 终结者】对 Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤 的简单介绍,ES搜索引擎无疑是最优秀的分布式搜索引擎,使用它,可大大提高项目的灵活、高效性!**
技术改变世界!!!
**
如果这篇【文章】有帮助到你,希望可以给【Bug 终结者】点个赞👍,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【Bug 终结者】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💝💝💝!
版权归原作者 Bug 终结者 所有, 如有侵权,请联系我们删除。