总结:
1.过滤功能分析
a.顶部导航已经选择的过滤条件
b.过滤条件展示,分类,品牌,规格参数
2.生成分类和品牌过滤(在搜索结果里,根据分类聚合所有商品,得到全部分类渲染到分类结果中)
a.应该根据搜索商品结果聚合出商品信息,品牌信息
应该根据用户搜索的结果,显示搜索的结果商品的全部分类和品牌信息。-- 从搜索的结果商品中聚合得到商品的分类,品牌信息。
2.1 扩展返回结果
PageResult只有total, totalPage, Items3个属性。但现在要根据用户搜索结果商品进行聚合,得到结果商品的分类,品牌信息。所以需要对返回结果进行扩展,添加分类和品牌的数据。
SearchResult
public class SearchResult extends PageResult
添加:private List<Map<String, Object>> categories;
private List brands;
2.2 实现功能:聚合商品分类和品牌
因为索引库中只要id, 所以要根据id聚合,然后再根据id去查询完整的数据。
所以商品微服务提供一个接口,根据品牌id集合,批量查询品牌。
修改SearchService中的search(SearchRequest request)方法, 增加聚合品牌和分类的功能
初始化自定义查询构建器
添加查询条件
添加结果集过滤,过滤掉字段,只需要id,subTitle, skus
获取分页参数,获取分页
添加3级分类,品牌聚合字段
执行搜索,获取搜索结果集
解析结果集,查询每个桶的分类id,再根据分类id添加分类对象,只添加部分字段到Map<String,Object>, 结果List<Map<String,Object>>)
解析结果集,查询每个桶的品牌id,再根据品牌id添加品牌对象,结果 List
结果:
2.3 规格参数的过滤(根据分类搜索结果聚合出所有分类)
用户搜索得到商品,并聚合出商品分类。
- 只有在聚合出的商品类=1 的情况下才去聚合商品规格,因为不同类下,规格参数不一样
判断用户分类数量是否等于1,如果是则进行规格参数聚合
根据分类,查找可以用来搜索的规格
对规格参数进行聚合,将规格参数聚合结果整理后返回。
3.2.1 扩展返回结果
public class SearchResult extends PageResult{
private List<Map<String, Object>> categories;
private List brands;
private List<Map<String, Object>> specs;
}
3.2.2.判断是否需要聚合,判断分类的个数,如果是1个则进行规格聚合:
3.2.3.获取需要聚合的规格参数
根据分类id, searching字段为true查询所有规格参数
3.2.4.聚合规格参数
聚合出规格参数
3.2.5.解析聚合结果
解析聚合结果,即将所有规格参数名和值放入:Map<String , Object>
测试结果:
- 了解过滤功能的基本思路
- 实现分类和品牌展示
- 了解规格参数展示
- 实现过滤条件筛选
- 实现已选过滤项回显
- 实现取消选择过滤项
1.过滤功能分析
首先看下页面要实现的效果:
整个过滤部分有3块:
- 顶部的导航,已经选择的过滤条件展示:
- 商品分类面包屑,根据用户选择的商品分类变化
- 其它已选择过滤参数
- 过滤条件展示,又包含3部分
- 商品分类展示
- 品牌展示
- 其它规格参数
- 展开或收起的过滤条件的按钮
顶部导航要展示的内容跟用户选择的过滤条件有关。
- 比如用户选择了某个商品分类,则面包屑中才会展示具体的分类
- 比如用户选择了某个品牌,列表中才会有品牌信息。
所以,这部分需要依赖第二部分:过滤条件的展示和选择。因此我们先不着急去做。
展开或收起的按钮是否显示,取决于过滤条件有多少,如果很少,那么就没必要展示。所以也是跟第二部分的过滤条件有关。
这样分析来看,我们必须先做第二部分:过滤条件展示。
2.1.扩展返回的结果
原来,我们返回的结果是PageResult对象,里面只有total、totalPage、items3个属性。但是现在要对商品分类和品牌进行聚合,数据显然不够用,我们需要对返回的结果进行扩展,添加分类和品牌的数据。
那么问题来了:以什么格式返回呢?
看页面:
分类:页面显示了分类名称,但背后肯定要保存id信息。所以至少要有id和name
品牌:页面展示的有logo,有文字,当然肯定有id,基本上是品牌的完整数据
我们新建一个类,继承PageResult,然后扩展两个新的属性:分类集合和品牌集合:
public class SearchResult extends PageResult<Goods> {
private List<Map<String, Object>> categories;
private List<Brand> brands;
public SearchResult() {
}
public SearchResult(List<Map<String, Object>> categories, List<Brand> brands) {
this.categories = categories;
this.brands = brands;
}
public SearchResult(List<Goods> items, Long total, List<Map<String, Object>> categories, List<Brand> brands) {
super(items, total);
this.categories = categories;
this.brands = brands;
}
public SearchResult(List<Goods> items, Long total, Integer totalPage, List<Map<String, Object>> categories, List<Brand> brands) {
super(items, total, totalPage);
this.categories = categories;
this.brands = brands;
}
public List<Map<String, Object>> getCategories() {
return categories;
}
public void setCategories(List<Map<String, Object>> categories) {
this.categories = categories;
}
public List<Brand> getBrands() {
return brands;
}
public void setBrands(List<Brand> brands) {
this.brands = brands;
}
}
2.2.聚合商品分类和品牌
我们修改搜索的业务逻辑,对分类和品牌聚合。
因为索引库中只有id,所以我们根据id聚合,然后再根据id去查询完整数据。
所以,商品微服务需要提供一个接口:根据品牌id集合,批量查询品牌。
修改SearchService:
public SearchResult search(SearchRequest request) {
// 判断查询条件
if (StringUtils.isBlank(request.getKey())) {
// 返回默认结果集
return null;
}
// 初始化自定义查询构建器
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加查询条件
queryBuilder.withQuery(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));
// 添加结果集过滤,只需要:id,subTitle, skus
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{
"id", "subTitle", "skus"}, null));
// 获取分页参数
Integer page = request.getPage();
Integer size = request.getSize();
// 添加分页
queryBuilder.withPageable(PageRequest.of(page - 1, size));
String categoryAggName = "categories";
String brandAggName = "brands";
queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));
// 执行搜索,获取搜索的结果集
AggregatedPage<Goods> goodsPage = (AggregatedPage<Goods>)this.goodsReponsitory.search(queryBuilder.build());
// 解析聚合结果集
List<Map<String, Object>> categories = getCategoryAggResult(goodsPage.getAggregation(categoryAggName));
List<Brand> brands = getBrandAggResult(goodsPage.getAggregation(brandAggName));
// 封装成需要的返回结果集
return new SearchResult(goodsPage.getContent(), goodsPage.getTotalElements(), goodsPage.getTotalPages(), categories, brands);
}
/**
* 解析品牌聚合结果集
* @param aggregation
* @return
*/
private List<Brand> getBrandAggResult(Aggregation aggregation) {
// 处理聚合结果集
LongTerms terms = (LongTerms)aggregation;
// 获取所有的品牌id桶
List<LongTerms.Bucket> buckets