黑马旅游,搜索,分页,条件过滤,我附近的酒店,广告置顶参考
RequestParams.java
package com.leo23.entity;
import lombok.Data;
/**
* @author 李建舜
* @version 1.0
* @date 2023/8/18 11:23
* @description
*/
@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;
}
PageResult.java
package com.leo23.entity;
import lombok.Data;
import java.util.List;
/**
* @author 李建舜
* @version 1.0
* @date 2023/8/18 11:24
* @description
*/
@Data
public class PageResult {
private Long total;
private List<HotelDoc> hotels;
public PageResult() {
}
public PageResult(Long total, List<HotelDoc> hotels) {
this.total = total;
this.hotels = hotels;
}
}
hotel.java
package com.leo23.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* (Hotel)表实体类
*
* @author makejava
* @since 2023-08-07 09:18:06
*/
@SuppressWarnings("serial")
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("tb_hotel")
public class Hotel {
//酒店id
private Long id;
//酒店名称
private String name;
//酒店地址
private String address;
//酒店价格
private Integer price;
//酒店评分
private Integer score;
//酒店品牌
private String brand;
//所在城市
private String city;
//酒店星级,1星到5星,1钻到5钻
private String starName;
//商圈
private String business;
//纬度
private String latitude;
//经度
private String longitude;
//酒店图片
private String pic;
}
HotelDoc.java
package com.leo23.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* (Hotel)表实体类
*
* @author makejava
* @since 2023-08-07 09:18:06
*/
@SuppressWarnings("serial")
@Data
@NoArgsConstructor
public class HotelDoc {
//酒店id
private Long id;
//酒店名称
private String name;
//酒店地址
private String address;
//酒店价格
private Integer price;
//酒店评分
private Integer score;
//酒店品牌
private String brand;
//所在城市
private String city;
//酒店星级,1星到5星,1钻到5钻
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();
}
}
ElasticSearchConfig.java
package com.leo23.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author leo
* @version 1.0
* @date 2023/8/18 11:27
* @description
*/
@Component
public class ElasticSearchConfig {
@Bean
public RestHighLevelClient client() {
return new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.50.178:9200")));
}
}
HotelDemoApplicationTests.java
package com.leo23;
import com.leo23.service.HotelService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class HotelDemoApplicationTests {
@Autowired
private HotelService hotelService;
@Test
void contextLoads() {
Map<String, List<String>> filters = hotelService.filters();
System.out.println(filters);
}
}
HotelServiceImpl.java
package com.leo23.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leo23.entity.HotelDoc;
import com.leo23.entity.PageResult;
import com.leo23.entity.RequestParams;
import com.leo23.mapper.HotelMapper;
import com.leo23.entity.Hotel;
import com.leo23.service.HotelService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* (Hotel)表服务实现类
*
* @author makejava
* @since 2023-08-07 09:18:07
*/
@Service("hotelService")
public class HotelServiceImpl extends ServiceImpl<HotelMapper, Hotel> implements HotelService {
@Autowired
private RestHighLevelClient client;
@Override
public Map<String, List<String>> filters(RequestParams params) {
try {
SearchRequest request = new SearchRequest("hotel");
// query
buildBasicQuery(params, request);
request.source().size(0);
buildAggreation(request);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
Map<String, List<String>> result = new HashMap<>();
Aggregations aggregations = response.getAggregations();
List<String> brandList = getAggreationByName(aggregations, "brandAgg");
result.put("brand", brandList);
List<String> cityList = getAggreationByName(aggregations, "cityAgg");
result.put("city", cityList);
List<String> starNameList = getAggreationByName(aggregations, "starNameAgg");
result.put("starName", starNameList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static List<String> getAggreationByName(Aggregations aggregations, String aggName) {
Terms brandTerms = aggregations.get(aggName);
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
List<String> brandList = new ArrayList<>();
for (Terms.Bucket bucket : buckets) {
String key = bucket.getKeyAsString();
brandList.add(key);
}
return brandList;
}
private static void buildAggreation(SearchRequest request) {
request.source().aggregation(AggregationBuilders.terms("brandAgg")
.field("brand")
.size(100));
request.source().aggregation(AggregationBuilders.terms("cityAgg")
.field("city")
.size(100));
request.source().aggregation(AggregationBuilders.terms("starNameAgg")
.field("starName")
.size(100));
}
@Override
public PageResult search(RequestParams params) {
try {
// 1准备request
SearchRequest request = new SearchRequest("hotel");
// 2准备DSL
buildBasicQuery(params, request);
// 关键字搜索,分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
// geo 排序
String location = params.getLocation();
if (!ObjectUtils.isEmpty(location)) {
request.source().sort(SortBuilders.geoDistanceSort("location", new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS));
}
// 发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void buildBasicQuery(RequestParams params, SearchRequest request) {
// 构建 boolQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 关键字
String key = params.getKey();
if (ObjectUtils.isEmpty(key)) {
boolQuery.must(QueryBuilders.matchAllQuery());
} else {
boolQuery.must(QueryBuilders.matchQuery("all", key));
}
// 条件过滤, city, brand, starName
if (!ObjectUtils.isEmpty(params.getCity())) {
boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
}
if (!ObjectUtils.isEmpty(params.getBrand())) {
boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
}
if (!ObjectUtils.isEmpty(params.getStarName())) {
boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
}
// 价格
if (!ObjectUtils.isEmpty(params.getMinPrice()) && !ObjectUtils.isEmpty(params.getMaxPrice())) {
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);
}
private PageResult handleResponse(SearchResponse response) {
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) {
hotelDoc.setDistance(sortValues[0]);
}
hotels.add(hotelDoc);
}
return new PageResult(total, hotels);
}
}
HotelController.java
package com.leo23.controller;
import com.leo23.entity.PageResult;
import com.leo23.entity.RequestParams;
import com.leo23.service.HotelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* (Hotel)表控制层
*
* @author makejava
* @since 2023-08-07 09:18:05
*/
@RestController
@RequestMapping("hotel")
public class HotelController {
@Autowired
private HotelService hotelService;
/**
* 服务对象
*/
@PostMapping("/list")
public PageResult search(@RequestBody RequestParams params) {
return hotelService.search(params);
}
@PostMapping("/filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams params){
return hotelService.filters(params);
}
}