package com.alatus.search.service.impl; import com.alatus.common.to.es.SkuEsModel; import com.alatus.search.config.MallElasticSearchConfig; import com.alatus.search.constant.EsConstant; import com.alatus.search.service.MallSearchService; 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.Aggregation; 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; @Service public class MallSearchServiceImpl implements MallSearchService { @Autowired private RestHighLevelClient client; @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); 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); // 分页信息页码 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); 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); } // 分页 if(searchParam.getPageNum()!=null){ sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE); sourceBuilder.size(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.alatus.search.config.MallElasticSearchConfig; import com.alatus.search.constant.EsConstant; import com.alatus.search.service.MallSearchService; 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.Aggregation; 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; @Service public class MallSearchServiceImpl implements MallSearchService { @Autowired private RestHighLevelClient client; @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); 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); // 分页信息页码 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); 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); } // 分页 if(searchParam.getPageNum()!=null){ sourceBuilder.from((searchParam.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE); sourceBuilder.size(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); } }