品牌、规格统计
品牌、规格统计与前一篇的种类分组统计是一样的,只需要进行分组查询,指定terms并根据terms获取统计结果即可,因此给出代码不在赘述
注意利用Bucket可以获得具体的结果
public Map search(Map<String, String> searchMap) {
//1.获取关键字的值
String keywords = searchMap.get("keywords");
if (StringUtils.isEmpty(keywords)) {
keywords = "华为";//赋值给一个默认的值
}
//2.创建查询对象 的构建对象
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//3.设置查询的条件
//设置分组条件 商品分类
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategorygroup").field("categoryName").size(50));
//设置分组条件 商品品牌
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandgroup").field("brandName").size(50));
//设置分组条件 商品的规格
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecgroup").field("spec.keyword").size(100));
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name", keywords));
//4.构建查询对象
NativeSearchQuery query = nativeSearchQueryBuilder.build();
//5.执行查询
AggregatedPage<SkuInfo> skuPage = esTemplate.queryForPage(query, SkuInfo.class);
//获取分组结果 商品分类
StringTerms stringTermsCategory = (StringTerms) skuPage.getAggregation("skuCategorygroup");
//获取分组结果 商品品牌
StringTerms stringTermsBrand = (StringTerms) skuPage.getAggregation("skuBrandgroup");
//获取分组结果 商品规格数据
StringTerms stringTermsSpec = (StringTerms) skuPage.getAggregation("skuSpecgroup");
List<String> categoryList = getStringsCategoryList(stringTermsCategory);
List<String> brandList = getStringsBrandList(stringTermsBrand);
Map<String, Set<String>> specMap = getStringSetMap(stringTermsSpec);
//6.返回结果
Map resultMap = new HashMap<>();
resultMap.put("specMap", specMap);
resultMap.put("categoryList", categoryList);
resultMap.put("brandList", brandList);
resultMap.put("rows", skuPage.getContent());
resultMap.put("total", skuPage.getTotalElements());
resultMap.put("totalPages", skuPage.getTotalPages());
return resultMap;
}
/**
* 获取品牌列表
*
* @param stringTermsBrand
* @return
*/
private List<String> getStringsBrandList(StringTerms stringTermsBrand) {
List<String> brandList = new ArrayList<>();
if (stringTermsBrand != null) {
for (StringTerms.Bucket bucket : stringTermsBrand.getBuckets()) {
brandList.add(bucket.getKeyAsString());
}
}
return brandList;
}
/**
* 获取分类列表数据
*
* @param stringTerms
* @return
*/
private List<String> getStringsCategoryList(StringTerms stringTerms) {
List<String> categoryList = new ArrayList<>();
if (stringTerms != null) {
for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
String keyAsString = bucket.getKeyAsString();//分组的值
categoryList.add(keyAsString);
}
}
return categoryList;
}
/**
* 获取规格列表数据
*
* @param stringTermsSpec
* @return
*/
private Map<String, Set<String>> getStringSetMap(StringTerms stringTermsSpec) {
Map<String, Set<String>> specMap = new HashMap<String, Set<String>>();
Set<String> specList = new HashSet<>();
if (stringTermsSpec != null) {
for (StringTerms.Bucket bucket : stringTermsSpec.getBuckets()) {
specList.add(bucket.getKeyAsString());
}
}
for (String specjson : specList) {
Map<String, String> map = JSON.parseObject(specjson, Map.class);
for (Map.Entry<String, String> entry : map.entrySet()) {//
String key = entry.getKey(); //规格名字
String value = entry.getValue(); //规格选项值
//获取当前规格名字对应的规格数据
Set<String> specValues = specMap.get(key);
if (specValues == null) {
specValues = new HashSet<String>();
}
//将当前规格加入到集合中
specValues.add(value);
//将数据存入到specMap中
specMap.put(key, specValues);
}
}
return specMap;
}
条件筛选
分类与品牌筛选
这是一个过滤查询,或者说是布尔查询的过程,依赖的是BoolQueryCuilder
类,主要涉及新建对象、设置过滤内容和为查询对象设置过滤查询三个步骤
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
完整代码如下
@Override
public Map search(Map<String, String> searchMap) {
//1.获取关键字的值
String keywords = searchMap.get("keywords");
if (StringUtils.isEmpty(keywords)) {
keywords = "华为";//赋值给一个默认的值
}
//2.创建查询对象 的构建对象
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//3.设置查询的条件
//设置分组条件 商品分类
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategorygroup").field("categoryName").size(50));
//设置分组条件 商品品牌
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandgroup").field("brandName").size(50));
//设置分组条件 商品的规格
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecgroup").field("spec.keyword").size(1000));
//设置主关键字查询
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name", keywords));
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
if (!StringUtils.isEmpty(searchMap.get("brand"))) {
boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
}
if (!StringUtils.isEmpty(searchMap.get("category"))) {
boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", searchMap.get("category")));
}
//构建过滤查询
nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
//4.构建查询对象
NativeSearchQuery query = nativeSearchQueryBuilder.build();
//5.执行查询
AggregatedPage<SkuInfo> skuPage = esTemplate.queryForPage(query, SkuInfo.class);
//获取分组结果 商品分类
StringTerms stringTermsCategory = (StringTerms) skuPage.getAggregation("skuCategorygroup");
//获取分组结果 商品品牌
StringTerms stringTermsBrand = (StringTerms) skuPage.getAggregation("skuBrandgroup");
//获取分组结果 商品规格数据
StringTerms stringTermsSpec = (StringTerms) skuPage.getAggregation("skuSpecgroup");
List<String> categoryList = getStringsCategoryList(stringTermsCategory);
List<String> brandList = getStringsBrandList(stringTermsBrand);
Map<String, Set<String>> specMap = getStringSetMap(stringTermsSpec);
//6.返回结果
Map resultMap = new HashMap<>();
resultMap.put("specMap", specMap);
resultMap.put("categoryList", categoryList);
resultMap.put("brandList", brandList);
resultMap.put("rows", skuPage.getContent());
resultMap.put("total", skuPage.getTotalElements());
resultMap.put("totalPages", skuPage.getTotalPages());
return resultMap;
}
价格过滤
分类与品牌过滤BoolQueryBuilder
采用的是QueryBuilders
的terms
,而价格过滤采用 的是range
//价格过滤查询
String price = searchMap.get("price");
if (!StringUtils.isEmpty(price)) {
String[] split = price.split("-");
if (!split[1].equalsIgnoreCase("*")) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(split[0], true).to(split[1], true));
} else {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(split[0]));
}
}
以上所有的过滤、分页都是对查询对象的
builder
对象进行了设置,这样通过build方法就可以直接输出符合要求的查询对象
搜索分页
过滤查询用的是withFilter
方法,分页是用withPageable
方法
//略
//构建过滤查询
nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
//构建分页查询
Integer pageNum = 1;
if (!StringUtils.isEmpty(searchMap.get("pageNum"))) {
try {
pageNum = Integer.valueOf(searchMap.get("pageNum"));
} catch (NumberFormatException e) {
e.printStackTrace();
pageNum=1;
}
}
Integer pageSize = 3;
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));
//略
//4.构建查询对象
NativeSearchQuery query = nativeSearchQueryBuilder.build();
//略
搜索排序
withSort
方法
//构建排序查询
String sortRule = searchMap.get("sortRule");
String sortField = searchMap.get("sortField");
if (!StringUtils.isEmpty(sortRule) && !StringUtils.isEmpty(sortField)) {
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortRule.equals("DESC") ? SortOrder.DESC : SortOrder.ASC));
}
高亮
修改com.changgou.search.service.impl.SkuServiceImpl的search方法搜索代码,添加高亮显示的域:
上图代码如下:
//设置高亮条件
nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name"));
nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em style=\"color:red\">").postTags("</em>"));
//设置主关键字查询
nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,"name","brandName","categoryName"));
修改 查询的方法,自定义结果映射器,入下图:
上图图片如下:
AggregatedPage<SkuInfo> skuPage = esTemplate.queryForPage(query, SkuInfo.class, new SearchResultMapperImpl());
自定义一个映射结果类实现接口,作用就是:自定义映射结果集,获取高亮的数据展示,如下图:
代码如下:
public class SearchResultMapperImpl implements SearchResultMapper {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<T> content = new ArrayList<>();
//如果没有结果返回为空
if (response.getHits() == null || response.getHits().getTotalHits() <= 0) {
return new AggregatedPageImpl<T>(content);
}
for (SearchHit searchHit : response.getHits()) {
String sourceAsString = searchHit.getSourceAsString();
SkuInfo skuInfo = JSON.parseObject(sourceAsString, SkuInfo.class);
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
HighlightField highlightField = highlightFields.get("name");
//有高亮则设置高亮的值
if (highlightField != null) {
StringBuffer stringBuffer = new StringBuffer();
for (Text text : highlightField.getFragments()) {
stringBuffer.append(text.string());
}
skuInfo.setName(stringBuffer.toString());
}
content.add((T) skuInfo);
}
return new AggregatedPageImpl<T>(content, pageable, response.getHits().getTotalHits(), response.getAggregations(), response.getScrollId());
}
}