package com.alatus.search.vo;
import lombok.Data;
@Data
public class AttrResponseVo {
// 分类名字
private String catelogName;
// 分组的名字
private String groupName;
// 菜单路径
private Long[] catelogPath;
/**
* 属性id
*/
private Long attrId;
/**
* 属性名
*/
private String attrName;
/**
* 是否需要检索[0-不需要,1-需要]
*/
private Integer searchType;
/**
* 值类型[0-为单个值,1-可以选择多个值]
*/
private Integer valueType;
/**
* 属性图标
*/
private String icon;
/**
* 可选值列表[用逗号分隔]
*/
private String valueSelect;
/**
* 属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]
*/
private Integer attrType;
/**
* 启用状态[0 - 禁用,1 - 启用]
*/
private Long enable;
/**
* 所属分类
*/
private Long catelogId;
/**
* 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整
*/
private Integer showDesc;
/**
* 分组ID
*/
private Long attrGroupId;
}
package com.alatus.search.vo;
import lombok.Data;
@Data
public class AttrResponseVo {
// 分类名字
private String catelogName;
// 分组的名字
private String groupName;
// 菜单路径
private Long[] catelogPath;
/**
* 属性id
*/
private Long attrId;
/**
* 属性名
*/
private String attrName;
/**
* 是否需要检索[0-不需要,1-需要]
*/
private Integer searchType;
/**
* 值类型[0-为单个值,1-可以选择多个值]
*/
private Integer valueType;
/**
* 属性图标
*/
private String icon;
/**
* 可选值列表[用逗号分隔]
*/
private String valueSelect;
/**
* 属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]
*/
private Integer attrType;
/**
* 启用状态[0 - 禁用,1 - 启用]
*/
private Long enable;
/**
* 所属分类
*/
private Long catelogId;
/**
* 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整
*/
private Integer showDesc;
/**
* 分组ID
*/
private Long attrGroupId;
}
package com.alatus.search.feign;
import com.alatus.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("Mall-product")
public interface ProductFeignService {
@GetMapping("/attr/info/{attrId}")
R info(@PathVariable("attrId") Long attrId);
}
package com.alatus.search.feign;
import com.alatus.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("Mall-product")
public interface ProductFeignService {
@GetMapping("/attr/info/{attrId}")
R info(@PathVariable("attrId") Long attrId);
}
package com.alatus.search.service.impl;
import com.alatus.common.to.es.SkuEsModel;
import com.alibaba.fastjson.TypeReference;
import com.alatus.common.utils.R;
import com.alatus.search.config.MallElasticSearchConfig;
import com.alatus.search.constant.EsConstant;
import com.alatus.search.feign.ProductFeignService;
import com.alatus.search.service.MallSearchService;
import com.alatus.search.vo.AttrResponseVo;
import com.alatus.search.vo.SearchParam;
import com.alatus.search.vo.SearchResult;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class MallSearchServiceImpl implements MallSearchService {
@Autowired
private RestHighLevelClient client;
@Autowired
private ProductFeignService productFeignService;
@Override
public SearchResult search(SearchParam searchParam) {
// 动态构建出查询所需要的DSL语句
SearchResult searchResult = null;
// 准备检索请求
SearchRequest searchRequest = buildSearchRequest(searchParam);
try {
// 执行查询检索请求
SearchResponse response = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);
// 分析响应数据并封装成返回的数据
searchResult = buildSearchResult(response,searchParam);
} catch (IOException e) {
throw new RuntimeException(e);
}
return searchResult;
}
private SearchResult buildSearchResult(SearchResponse response,SearchParam searchParam) {
SearchResult result = new SearchResult();
SearchHits hits = response.getHits();
// 返回所有查询到的商品
if(hits.getHits()!=null&&hits.getHits().length>0){
List<SkuEsModel> skuEsModelList = new ArrayList<>();
for (SearchHit hit : hits.getHits()) {
String sourceAsString = hit.getSourceAsString();
SkuEsModel skuEsModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
if(!StringUtils.isEmpty(searchParam.getKeyword())){
//拿到高亮信息显示标题
skuEsModel.setSkuTitle(hit.getHighlightFields().get("skuTitle").getFragments()[0].toString());
}
skuEsModelList.add(skuEsModel);
}
result.setProducts(skuEsModelList);
}
// 当前涉及到的所有属性信息
ParsedNested attrAgg = response.getAggregations().get("attr_agg");
ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attr_id_agg");
List<SearchResult.AttrVo> attrVoList = new ArrayList<>();
for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
// 设置属性ID
attrVo.setAttrId(Long.parseLong(bucket.getKeyAsString()));
// 设置属性名字
ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attr_name_agg");
attrVo.setAttrName(attrNameAgg.getBuckets().get(0).getKeyAsString());
// 设置属性值
ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attr_value_agg");
List<String> attrValue = new ArrayList<>();
for (Terms.Bucket attrValueAggBucket : attrValueAgg.getBuckets()) {
attrValue.add(attrValueAggBucket.getKeyAsString());
}
attrVo.setAttrValue(attrValue);
attrVoList.add(attrVo);
}
result.setAttrs(attrVoList);
// 当前商品涉及到的所有品牌信息
ParsedLongTerms brandAgg = response.getAggregations().get("brand_agg");
List<SearchResult.BrandVo> brandVoList = new ArrayList<>();
for (Terms.Bucket bucket : brandAgg.getBuckets()) {
SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
// 设置品牌ID
brandVo.setBrandId(Long.parseLong(bucket.getKeyAsString()));
// 设置品牌名字
ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brand_name_agg");
brandVo.setBrandName(brandNameAgg.getBuckets().get(0).getKeyAsString());
// 设置品牌图片
ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brand_img_agg");
brandVo.setBrandImg(brandImgAgg.getBuckets().get(0).getKeyAsString());
brandVoList.add(brandVo);
}
result.setBrands(brandVoList);
// 当前商品涉及到的所有分类信息
ParsedLongTerms catalogAgg = response.getAggregations().get("catalog_agg");
List<SearchResult.CatalogVo> catalogVoList = new ArrayList<>();
for (Terms.Bucket bucket : catalogAgg.getBuckets()) {
SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
// 设置分类ID
catalogVo.setCatalogId(Long.parseLong(bucket.getKeyAsString()));
// 获取分类ID下分类名字的子聚合
ParsedStringTerms catalogNameAgg = bucket.getAggregations().get("catalog_name_agg");
// 设置分类名字
catalogVo.setCatalogName(catalogNameAgg.getBuckets().get(0).getKeyAsString());
catalogVoList.add(catalogVo);
}
result.setCatalogs(catalogVoList);
// 分页信息页码
if(searchParam.getPageNum()!=null){
result.setPageNum(searchParam.getPageNum());
}
// 总记录数
long total = hits.getTotalHits().value;
result.setTotal(total);
// 总页码
Integer totalPage = ((total%EsConstant.PRODUCT_PAGESIZE==0)?(int)(total/EsConstant.PRODUCT_PAGESIZE):(int)((total/EsConstant.PRODUCT_PAGESIZE)+1));
result.setTotalPages(totalPage);
// 构建面包屑导航
List<SearchResult.NavVo> navVoList = searchParam.getAttrs().stream().map(attr -> {
// 分析每一个传递的Attr信息,构建navVo
SearchResult.NavVo navVo = new SearchResult.NavVo();
String[] attrs = attr.split("_");
navVo.setNavValue(attrs[1]);
R info = productFeignService.info(Long.parseLong(attrs[0]));
if(info.getCode()==0){
String dataString = JSON.toJSONString(info.get("attr"));
navVo.setNavName(JSON.parseObject(dataString, new TypeReference<AttrResponseVo>(){}).getAttrName());
}
else{
navVo.setNavName(attrs[0]);
}
// TODO 取消面包屑以后,我们怎么跳转
return navVo;
}).collect(Collectors.toList());
result.setNavs(navVoList);
return result;
}
//准备检索请求
private SearchRequest buildSearchRequest(SearchParam searchParam) {
// 构建DSL语句
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 查询条件,模糊查询,过滤,按照属性,分类品牌,价格区间,库存
// 构建了bool-query
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// must
if(!StringUtils.isEmpty(searchParam.getKeyword())){
boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
}
// filter按照三级分类ID查询
if(searchParam.getCatalog3Id()!=null){
boolQuery.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
}
// filter按照品牌ID查询
if(searchParam.getBrandId()!=null && !searchParam.getBrandId().isEmpty()){
boolQuery.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
}
// filter按照属性ID查询
if(searchParam.getAttrs()!=null && !searchParam.getAttrs().isEmpty()){
for (String attrStr : searchParam.getAttrs()) {
BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
String[] attr = attrStr.split("_");
String attrId = attr[0];//属性ID
String[] attrValues = attr[1].split(":");//属性值
nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));
nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));
// 每一个都必须有一个嵌入式的查询
NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
boolQuery.filter(attrs);
}
}
// 按照库存进行查询
if(searchParam.getHasStock()!=null){
boolQuery.filter(QueryBuilders.termQuery("hasStock", searchParam.getHasStock()==1));
}
// 按照价格区间
if(!StringUtils.isEmpty(searchParam.getSkuPrice())){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
String[] price = searchParam.getSkuPrice().split("_");
if(price.length == 2){
rangeQuery.gte(price[0]).lte(price[1]);
}
else if (price.length == 1) {
if(searchParam.getSkuPrice().startsWith("_")){
rangeQuery.lte(price[0]);
}
else if(searchParam.getSkuPrice().endsWith("_")){
rangeQuery.gte(price[0]);
}
}
boolQuery.filter(rangeQuery);
}
// 把所有条件全部封装
sourceBuilder.query(boolQuery);
// 排序
if(!StringUtils.isEmpty(searchParam.getSort())){
String sort = searchParam.getSort();
String[] sortString = sort.split("_");
sourceBuilder.sort(sortString[0],sortString[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC);
}
// 分页
sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);
if(searchParam.getPageNum()!=null){
sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE);
}
// 高亮
if (!StringUtils.isEmpty(searchParam.getKeyword())){
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("skuTitle");
highlightBuilder.preTags("<b style='color:red'>");
highlightBuilder.postTags("</b>");
sourceBuilder.highlighter(highlightBuilder);
}
// 品牌聚合
TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg").field("brandId").size(50);
// 品牌聚合的品牌名字子聚合
brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));
// 品牌聚合的品牌图片子聚合
brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));
// 把品牌聚合放里面
sourceBuilder.aggregation(brandAgg);
// 分类聚合
TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(50);
// 分类聚合的品牌名字子聚合
catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));
// 把分类聚合放里面
sourceBuilder.aggregation(catalogAgg);
// 属性聚合
NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attr_agg", "attrs");
// 属性ID聚合查询
TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId").size(50);
// 属性名子聚合
attrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));
// 属性值子聚合
attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));
// 把属性ID聚合查询放进属性内嵌查询
attrAgg.subAggregation(attrIdAgg);
// 把属性聚合放里面
sourceBuilder.aggregation(attrAgg);
return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX},sourceBuilder);
}
}
package com.alatus.search.service.impl;
import com.alatus.common.to.es.SkuEsModel;
import com.alibaba.fastjson.TypeReference;
import com.alatus.common.utils.R;
import com.alatus.search.config.MallElasticSearchConfig;
import com.alatus.search.constant.EsConstant;
import com.alatus.search.feign.ProductFeignService;
import com.alatus.search.service.MallSearchService;
import com.alatus.search.vo.AttrResponseVo;
import com.alatus.search.vo.SearchParam;
import com.alatus.search.vo.SearchResult;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class MallSearchServiceImpl implements MallSearchService {
@Autowired
private RestHighLevelClient client;
@Autowired
private ProductFeignService productFeignService;
@Override
public SearchResult search(SearchParam searchParam) {
// 动态构建出查询所需要的DSL语句
SearchResult searchResult = null;
// 准备检索请求
SearchRequest searchRequest = buildSearchRequest(searchParam);
try {
// 执行查询检索请求
SearchResponse response = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);
// 分析响应数据并封装成返回的数据
searchResult = buildSearchResult(response,searchParam);
} catch (IOException e) {
throw new RuntimeException(e);
}
return searchResult;
}
private SearchResult buildSearchResult(SearchResponse response,SearchParam searchParam) {
SearchResult result = new SearchResult();
SearchHits hits = response.getHits();
// 返回所有查询到的商品
if(hits.getHits()!=null&&hits.getHits().length>0){
List<SkuEsModel> skuEsModelList = new ArrayList<>();
for (SearchHit hit : hits.getHits()) {
String sourceAsString = hit.getSourceAsString();
SkuEsModel skuEsModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
if(!StringUtils.isEmpty(searchParam.getKeyword())){
//拿到高亮信息显示标题
skuEsModel.setSkuTitle(hit.getHighlightFields().get("skuTitle").getFragments()[0].toString());
}
skuEsModelList.add(skuEsModel);
}
result.setProducts(skuEsModelList);
}
// 当前涉及到的所有属性信息
ParsedNested attrAgg = response.getAggregations().get("attr_agg");
ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attr_id_agg");
List<SearchResult.AttrVo> attrVoList = new ArrayList<>();
for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
// 设置属性ID
attrVo.setAttrId(Long.parseLong(bucket.getKeyAsString()));
// 设置属性名字
ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attr_name_agg");
attrVo.setAttrName(attrNameAgg.getBuckets().get(0).getKeyAsString());
// 设置属性值
ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attr_value_agg");
List<String> attrValue = new ArrayList<>();
for (Terms.Bucket attrValueAggBucket : attrValueAgg.getBuckets()) {
attrValue.add(attrValueAggBucket.getKeyAsString());
}
attrVo.setAttrValue(attrValue);
attrVoList.add(attrVo);
}
result.setAttrs(attrVoList);
// 当前商品涉及到的所有品牌信息
ParsedLongTerms brandAgg = response.getAggregations().get("brand_agg");
List<SearchResult.BrandVo> brandVoList = new ArrayList<>();
for (Terms.Bucket bucket : brandAgg.getBuckets()) {
SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
// 设置品牌ID
brandVo.setBrandId(Long.parseLong(bucket.getKeyAsString()));
// 设置品牌名字
ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brand_name_agg");
brandVo.setBrandName(brandNameAgg.getBuckets().get(0).getKeyAsString());
// 设置品牌图片
ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brand_img_agg");
brandVo.setBrandImg(brandImgAgg.getBuckets().get(0).getKeyAsString());
brandVoList.add(brandVo);
}
result.setBrands(brandVoList);
// 当前商品涉及到的所有分类信息
ParsedLongTerms catalogAgg = response.getAggregations().get("catalog_agg");
List<SearchResult.CatalogVo> catalogVoList = new ArrayList<>();
for (Terms.Bucket bucket : catalogAgg.getBuckets()) {
SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
// 设置分类ID
catalogVo.setCatalogId(Long.parseLong(bucket.getKeyAsString()));
// 获取分类ID下分类名字的子聚合
ParsedStringTerms catalogNameAgg = bucket.getAggregations().get("catalog_name_agg");
// 设置分类名字
catalogVo.setCatalogName(catalogNameAgg.getBuckets().get(0).getKeyAsString());
catalogVoList.add(catalogVo);
}
result.setCatalogs(catalogVoList);
// 分页信息页码
if(searchParam.getPageNum()!=null){
result.setPageNum(searchParam.getPageNum());
}
// 总记录数
long total = hits.getTotalHits().value;
result.setTotal(total);
// 总页码
Integer totalPage = ((total%EsConstant.PRODUCT_PAGESIZE==0)?(int)(total/EsConstant.PRODUCT_PAGESIZE):(int)((total/EsConstant.PRODUCT_PAGESIZE)+1));
result.setTotalPages(totalPage);
// 构建面包屑导航
List<SearchResult.NavVo> navVoList = searchParam.getAttrs().stream().map(attr -> {
// 分析每一个传递的Attr信息,构建navVo
SearchResult.NavVo navVo = new SearchResult.NavVo();
String[] attrs = attr.split("_");
navVo.setNavValue(attrs[1]);
R info = productFeignService.info(Long.parseLong(attrs[0]));
if(info.getCode()==0){
String dataString = JSON.toJSONString(info.get("attr"));
navVo.setNavName(JSON.parseObject(dataString, new TypeReference<AttrResponseVo>(){}).getAttrName());
}
else{
navVo.setNavName(attrs[0]);
}
// TODO 取消面包屑以后,我们怎么跳转
return navVo;
}).collect(Collectors.toList());
result.setNavs(navVoList);
return result;
}
//准备检索请求
private SearchRequest buildSearchRequest(SearchParam searchParam) {
// 构建DSL语句
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 查询条件,模糊查询,过滤,按照属性,分类品牌,价格区间,库存
// 构建了bool-query
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// must
if(!StringUtils.isEmpty(searchParam.getKeyword())){
boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
}
// filter按照三级分类ID查询
if(searchParam.getCatalog3Id()!=null){
boolQuery.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
}
// filter按照品牌ID查询
if(searchParam.getBrandId()!=null && !searchParam.getBrandId().isEmpty()){
boolQuery.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
}
// filter按照属性ID查询
if(searchParam.getAttrs()!=null && !searchParam.getAttrs().isEmpty()){
for (String attrStr : searchParam.getAttrs()) {
BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
String[] attr = attrStr.split("_");
String attrId = attr[0];//属性ID
String[] attrValues = attr[1].split(":");//属性值
nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));
nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));
// 每一个都必须有一个嵌入式的查询
NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
boolQuery.filter(attrs);
}
}
// 按照库存进行查询
if(searchParam.getHasStock()!=null){
boolQuery.filter(QueryBuilders.termQuery("hasStock", searchParam.getHasStock()==1));
}
// 按照价格区间
if(!StringUtils.isEmpty(searchParam.getSkuPrice())){
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
String[] price = searchParam.getSkuPrice().split("_");
if(price.length == 2){
rangeQuery.gte(price[0]).lte(price[1]);
}
else if (price.length == 1) {
if(searchParam.getSkuPrice().startsWith("_")){
rangeQuery.lte(price[0]);
}
else if(searchParam.getSkuPrice().endsWith("_")){
rangeQuery.gte(price[0]);
}
}
boolQuery.filter(rangeQuery);
}
// 把所有条件全部封装
sourceBuilder.query(boolQuery);
// 排序
if(!StringUtils.isEmpty(searchParam.getSort())){
String sort = searchParam.getSort();
String[] sortString = sort.split("_");
sourceBuilder.sort(sortString[0],sortString[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC);
}
// 分页
sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);
if(searchParam.getPageNum()!=null){
sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE);
}
// 高亮
if (!StringUtils.isEmpty(searchParam.getKeyword())){
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("skuTitle");
highlightBuilder.preTags("<b style='color:red'>");
highlightBuilder.postTags("</b>");
sourceBuilder.highlighter(highlightBuilder);
}
// 品牌聚合
TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg").field("brandId").size(50);
// 品牌聚合的品牌名字子聚合
brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));
// 品牌聚合的品牌图片子聚合
brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));
// 把品牌聚合放里面
sourceBuilder.aggregation(brandAgg);
// 分类聚合
TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg").field("catalogId").size(50);
// 分类聚合的品牌名字子聚合
catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));
// 把分类聚合放里面
sourceBuilder.aggregation(catalogAgg);
// 属性聚合
NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attr_agg", "attrs");
// 属性ID聚合查询
TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId").size(50);
// 属性名子聚合
attrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));
// 属性值子聚合
attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));
// 把属性ID聚合查询放进属性内嵌查询
attrAgg.subAggregation(attrIdAgg);
// 把属性聚合放里面
sourceBuilder.aggregation(attrAgg);
return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX},sourceBuilder);
}
}