携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情
每日英语:
One sees clearly only with the heart;What is essential is invisible to the eye.
翻译:只有用心才能看清真相,真正重要的东西用眼睛是看不到的。 ——《小王子》
1. 商品搜索条件属性回显
1.1 属性条件回显分析
属性条件其实就是当前搜索的所有商品属性信息,所以我们可以把所有属性信息全部查询出来,然后把属性名作为key,属性值用集合存起来,就是我们页面要的属性条件了。
1.2 属性条件回显查询
1.2.1 属性分组查询
修改com.xz.mall.search.service.impl.SkuSearchServiceImpl的group方法,添加分组查询,代码如下:
/**
* 分组搜素
* @param queryBuilder
* @param searchMap
* @return
*/
private void group(NativeSearchQueryBuilder queryBuilder, Map<String, Object> searchMap) {
//用户如果没有输入分类条件,则需要将分类搜索出来,作为条件提供给用户
if (StringUtils.isEmpty(searchMap.get("category"))) {
queryBuilder.addAggregation(
AggregationBuilders
.terms("categoryList")//别名,类似Map的key
.field("categoryName")//根据categoryName域进行分组
.size(100)//分组结果显示100个
);
}
//用户如果没有输入品牌条件,则需要将分类搜索出来,作为条件提供给用户
if (StringUtils.isEmpty(searchMap.get("brand"))) {
queryBuilder.addAggregation(
AggregationBuilders
.terms("brandList")//别名,类似Map的key
.field("brandName")//根据brandName域进行分组
.size(100)//分组结果显示100个
);
}
//属性分组查询
queryBuilder.addAggregation(
AggregationBuilders
.terms("attrmaps")//别名,类似Map的key
.field("skuAttribute")//根据skuAttribute域进行分组
.size(100000)//分组结果显示100000个
);
}
1.2.2 属性数据分析
在com.xz.mall.search.service.impl.SkuSearchServiceImpl中添加attrParse方法,添加熟悉数据分析方法,代码如下:
/**
* 属性数据分析
* @param searchMap
*/
private void attrParse(Map<String, Object> searchMap) {
//先获取attrMaps
Object attrMaps = searchMap.get("attrmaps");
if (!ObjectUtils.isEmpty(attrMaps)) {
//集合数据
List<String> groupList = (List<String>) attrMaps;
//定义一个集合Map<String,Set<String>>,存储所有汇总数据
Map<String, Set<String>> allMaps = new HashMap<>();
//循环集合
for (String attr : groupList) {
Map<String, String> attrMap = JSON.parseObject(attr, Map.class);
for (Map.Entry<String, String> entry : attrMap.entrySet()) {
//获取每条记录,将记录转成Map
String key = entry.getKey();
Set<String> values = allMaps.get(key);
if (values == null) {
values = new HashSet<>();
}
//存在,则取出来,再添加当前值
values.add(entry.getValue());
//覆盖之前的数据
allMaps.put(key,values);
}
}
//覆盖之前的attrMaps
searchMap.put("attrmaps", allMaps);
}
}
1.2.3 执行调用
在com.xz.mall.search.service.impl.SkuSearchServiceImpl#search中执行调用,如下代码:
/**
* 商品关键词搜索
* @param searchMap
* @return
*/
@Override
public Map<String, Object> search(Map<String, Object> searchMap) {
//QueryBuilder->构建搜索条件
NativeSearchQueryBuilder queryBuilder = queryBuilder(searchMap);
//分组搜索调用
group(queryBuilder, searchMap);
//skuSearchMapper进行搜索
//Page<SkuEs> page = skuSearchMapper.search(queryBuilder.build());
AggregatedPage<SkuEs> page = (AggregatedPage<SkuEs>) skuSearchMapper.search(queryBuilder.build());
//获取结果集:集合列表、记录总数
Map<String, Object> resultMap = new HashMap<>();
//分组数据解析
parseGroup(page.getAggregations(), resultMap);
//动态属性解析
attrParse(resultMap);
List<SkuEs> list = page.getContent();
resultMap.put("list", list);
resultMap.put("totalElements", page.getTotalElements());
return resultMap;
}
2. 商品搜索条件筛选实现
2.1 搜索条件筛选分析
用户在前端执行条件搜索的时候,有可能会选择分类、品牌、价格、属性,每次选择条件传入后台,后台按照指定参数进行条件查询,我们这里制定一个传参数的规则:
1、分类参数:category
2、品牌参数:brand
3、价格参数:price
4、属性参数:attr_属性名:属性值
5、分页参数:page
2.2 条件筛选查询实现
2.2.1 分类、品牌、价格查询
分别获取category,brand,price的值,并根据这三个只分别实现分类过滤、品牌过滤、价格过滤,其中价格过滤传入的数据以-分割,实现代码如下:
修改com.xz.mall.search.service.impl.SkuSearchServiceImpl#queryBuilder添加代码,完整代码如下图:
/**
* 搜索条件构建
* @param searchMap
* @return
*/
private NativeSearchQueryBuilder queryBuilder(Map<String, Object> searchMap) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//组合查询对象
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//判断关键词是否为空,不为空,则设置条件
if (!CollectionUtils.isEmpty(searchMap)) {
//获取关键词
Object keyWords = searchMap.get("keywords");
if (!ObjectUtils.isEmpty(keyWords)) {
boolQueryBuilder.must(QueryBuilders.termQuery("name", keyWords.toString()));
}
//分类查询
Object category = searchMap.get("category");
if (!ObjectUtils.isEmpty(category)) {
boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", category.toString()));
}
//品牌查询
Object brand = searchMap.get("brand");
if (!ObjectUtils.isEmpty(brand)) {
boolQueryBuilder.must(QueryBuilders.termQuery("brandName", brand.toString()));
}
//价格区间查询 price 0-500元 500-1000元 1000元以上
Object price = searchMap.get("price");
if (!ObjectUtils.isEmpty(price)) {
String[] prices = price.toString().replace("元", "").replace("以上", "").split("-");
//price > x
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.valueOf(prices[0])));
//price <= y
if (prices.length == 2) {
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.valueOf(prices[1])));
}
}
}
return queryBuilder.withQuery(boolQueryBuilder);
}
2.2.2 分页查询
编写分页实现,先获取当前页,再在com.xz.mall.search.service.impl.SkuSearchServiceImpl#queryBuilder调用该方法。
2.2.2.1 获取当前分页方法
/**
* 获取当前分页
* @param searchMap
* @return
*/
private int currentPage(Map<String, Object> searchMap) {
try {
Object page = searchMap.get("page");
return Integer.valueOf(page.toString()) - 1;
} catch (Exception e) {
return 0;
}
}
2.2.2.2 分页调用
在com.xz.mall.search.service.impl.SkuSearchServiceImpl#queryBuilder中添加一下调用
//分页查询
queryBuilder.withPageable(PageRequest.of(currentPage(searchMap), 5));
2.2.3 属性查询
属性查询,每次传到后台的参数都是以attr_开始,我们可以遍历传过来的参数searchMap,判断是否是以attr_开始的参数,如果是,则查询属性。
在com.xz.mall.search.service.impl.SkuSearchServiceImpl#queryBuilder中添加如下代码 即可:
//动态属性查询
for (Map.Entry<String, Object> entry : searchMap.entrySet()) {
//以attr_开始,动态属性
if (entry.getKey().startsWith("attr_")) {
String key = "attrMap." + entry.getKey().replaceFirst("attr_", "") + ".keyword";
boolQueryBuilder.must(QueryBuilders.termQuery(key, entry.getValue().toString()));
}
}
最终完整代码如下图:
/**
* 搜索条件构建
* @param searchMap
* @return
*/
private NativeSearchQueryBuilder queryBuilder(Map<String, Object> searchMap) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//组合查询对象
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//判断关键词是否为空,不为空,则设置条件
if (!CollectionUtils.isEmpty(searchMap)) {
//获取关键词
Object keyWords = searchMap.get("keywords");
if (!ObjectUtils.isEmpty(keyWords)) {
boolQueryBuilder.must(QueryBuilders.termQuery("name", keyWords.toString()));
}
//分类查询
Object category = searchMap.get("category");
if (!ObjectUtils.isEmpty(category)) {
boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", category.toString()));
}
//品牌查询
Object brand = searchMap.get("brand");
if (!ObjectUtils.isEmpty(brand)) {
boolQueryBuilder.must(QueryBuilders.termQuery("brandName", brand.toString()));
}
//价格区间查询 price 0-500元 500-1000元 1000元以上
Object price = searchMap.get("price");
if (!ObjectUtils.isEmpty(price)) {
String[] prices = price.toString().replace("元", "").replace("以上", "").split("-");
//price > x
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.valueOf(prices[0])));
//price <= y
if (prices.length == 2) {
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.valueOf(prices[1])));
}
}
//动态属性查询
for (Map.Entry<String, Object> entry : searchMap.entrySet()) {
//以attr_开始,动态属性
if (entry.getKey().startsWith("attr_")) {
String key = "attrMap." + entry.getKey().replaceFirst("attr_", "") + ".keyword";
boolQueryBuilder.must(QueryBuilders.termQuery(key, entry.getValue().toString()));
}
}
}
//分页查询
queryBuilder.withPageable(PageRequest.of(currentPage(searchMap), 5));
return queryBuilder.withQuery(boolQueryBuilder);
}
总结:
本篇主要介绍了一下商品搜索条件属性回显的具体实现,还有商品搜索条件筛选查询的具体实现。