需求:
搜索页面的品牌、城市等信息不应该是在页面写死,而是通过聚合索引库中的酒店数据得来的
1、确定前端请求的接口和返回值格式:
返回值类型就是页面要展示的最终结果:
结果是一个Map结构:
key是字符串,城市、星级、品牌、价格
value是集合,例如多个城市的名称
2、代码实现:
controller层:
/**
* 聚合:城市、星级、品牌
*/
@PostMapping("filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams params){
return hotelService.filters(params);
}
service层:
/**
* 聚合:城市、星级、品牌
*/
Map<String, List<String>> filters(RequestParams params);
serviceimpl层:实现层
@Override
public Map<String, List<String>> filters(RequestParams params) {
try {
// 1.准备Request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1.设置查询条件
buildBasicQuery(params, request);
// 2.2.设置size
request.source().size(0);//不在结果中包含文档详情
// 2.3.聚合
buildAggregation(request);
// 3.发出请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
Map<String, List<String>> result = new HashMap<>();
Aggregations aggregations = response.getAggregations();
// 4.1.根据品牌名称,获取品牌结果
List<String> brandList = getAggByName(aggregations, "brandAgg");
result.put("brand", brandList);
// 4.2.根据品牌名称,获取品牌结果
List<String> cityList = getAggByName(aggregations, "cityAgg");
result.put("city", cityList);
// 4.3.根据品牌名称,获取品牌结果
List<String> starList = getAggByName(aggregations, "starAgg");
result.put("starName", starList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* AggregationBuilders 工具类
* terms 桶聚合--分组汇总,聚合的类型,按照品牌值聚合
* field 按照哪个字段分组
* size(50) 显示的数量
*/
private void buildAggregation(SearchRequest request) {
request.source().aggregation(AggregationBuilders
.terms("cityAgg")
.field("city")
.size(50)
);
request.source().aggregation(AggregationBuilders
.terms("starAgg")
.field("starName")
.size(50)
);
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(50)
);
}
private List<String> getAggByName(Aggregations aggregations, String aggName) {
// 4.1.根据聚合名称获取聚合结果
Terms brandTerms = aggregations.get(aggName);
// 4.2.获取buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
// 4.3.遍历
List<String> brandList = new ArrayList<>();
for (Terms.Bucket bucket : buckets) {
// 4.4.获取key
String key = bucket.getKeyAsString();
brandList.add(key);
}
return brandList;
}
private void buildBasicQuery(RequestParams params, SearchRequest request) {
// 1.构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 2.关键字搜索
if (StringUtils.isBlank(params.getKey())) {
boolQuery.must(QueryBuilders.matchAllQuery());
} else {
boolQuery.must(QueryBuilders.matchQuery("name", params.getKey()));
}
// 3.城市条件
if (StringUtils.isNotBlank(params.getCity())) {
boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
}
// 4.品牌条件
if (StringUtils.isBlank(params.getBrand())) {
boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
}
// 5.星级条件
if (StringUtils.isBlank(params.getStarName())) {
boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
}
// 6.价格
if (params.getMinPrice() != null && params.getMaxPrice() != null) {
boolQuery.filter(QueryBuilders
.rangeQuery("price")
.gte(params.getMinPrice())
.lte(params.getMaxPrice())
);
}
// 7.放入source
request.source().query(boolQuery);
}