@Service("SearchServiceImpl")public class SearchServiceImpl implements MallSearchService { @Autowired private RestHighLevelClient restHighLevelClient; @Override public SearchResult search(SearchParam searchParam) { SearchResult result = null; //1.检索请求 SearchRequest searchRequest = buildSearchRequest(searchParam); try { //2.执行请求 SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); //3.分析响应数据, 封装成我们需要的格式 result = buildSearchResult(response, searchParam); } catch (IOException e) { e.printStackTrace(); } return result; } private SearchRequest buildSearchRequest(SearchParam param) { //1.指定DSL检索条件, 构建查询语句 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); /* 查询: 模糊匹配, 过滤(按照属性/分类/品牌/价格区间/库存) */ //1.1 must-skuTitle if (StringUtils.isNotEmpty(param.getKeyword())) { boolQuery.must(QueryBuilders.termQuery("skuTitle", param.getKeyword())); } //1.2 filter过滤查询 if (param.getCatalog3Id() != null) { boolQuery.filter(QueryBuilders.termQuery("catelogId", param.getCatalog3Id())); } if (param.getBrandId() != null && param.getBrandId().size() > 0) { TermsQueryBuilder termsQuery = QueryBuilders.termsQuery("brandId", param.getBrandId()); boolQuery.filter(termsQuery); } if (param.getAttrs() != null && param.getAttrs().size() > 0) { for (String attr : param.getAttrs()) { BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery(); //attrs=1_a13:b14&attrs=2_2018:2019 String[] s = attr.split("_"); String attrId = s[0]; String[] attrValues = s[1].split(":"); nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId", attrId)); nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue", attrValues)); NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None); boolQuery.filter(nestedQuery); } } if (param.getHasStock() != null) { boolQuery.filter(QueryBuilders.termQuery("hasStock", param.getHasStock() == 1)); } if (param.getSkuPrice() != null) { RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice"); //4000_6000/_6000/4000_ String[] s = param.getSkuPrice().split("_"); if (param.getSkuPrice().endsWith("_")) { rangeQuery.gte(s[0]); } else { rangeQuery.gte(s[0]).lte(s[1]); } boolQuery.filter(rangeQuery); } sourceBuilder.query(boolQuery); /* 排序, 分页, 高亮 */ //2.1 排序 skuPrice_asc/desc if (StringUtils.isNotEmpty(param.getSort())) { String sort = param.getSort(); String[] s = sort.split("_"); SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC; sourceBuilder.sort(s[0], order); } //2.2 分页 pageSize: 5 // pageNum:1 from:0 size:5 [0,1,2,3,4] // pageNum:2 from:5 size:5 [5,6,7,8,9] // from = (pageNum-1)*size sourceBuilder.from((param.getPageNum() - 1) * EsConstant.PRODUCT_PAGESIZE); sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE); //2.3 高亮 if (StringUtils.isNotEmpty(param.getKeyword())) { HighlightBuilder builder = new HighlightBuilder(); builder.field("skuTitle"); builder.preTags("<b style='color:red'>"); builder.postTags("</b>"); sourceBuilder.highlighter(builder); } /** * 聚合分析 */ //1.品牌聚合 TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg").field("brandId"); TermsAggregationBuilder brand_name_agg = AggregationBuilders.terms("brand_name_agg").field("brandName").size(1); TermsAggregationBuilder brand_img_agg = AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1); brand_agg.subAggregation(brand_name_agg); brand_agg.subAggregation(brand_img_agg); sourceBuilder.aggregation(brand_agg); //2.分类聚合 TermsAggregationBuilder catelog_agg = AggregationBuilders.terms("catelog_agg").field("catelogId"); TermsAggregationBuilder catelog_name_agg = AggregationBuilders.terms("catelog_name_agg").field("catelogName").size(1); catelog_agg.subAggregation(catelog_name_agg); sourceBuilder.aggregation(catelog_agg); //3.属性聚合 NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs"); TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId"); TermsAggregationBuilder attr_name_agg = AggregationBuilders.terms("attr_name_agg").field("attrs.attrName"); TermsAggregationBuilder attr_value_agg = AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue"); attr_id_agg.subAggregation(attr_name_agg); attr_id_agg.subAggregation(attr_value_agg); attr_agg.subAggregation(attr_id_agg); sourceBuilder.aggregation(attr_agg); System.out.println("构造的DSL" + sourceBuilder.toString()); return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX}, sourceBuilder); } private SearchResult buildSearchResult(SearchResponse response, SearchParam param) { SearchResult result = new SearchResult(); SearchHits hits = response.getHits(); List<SkuEsModelTo> skuEsModelTos = Arrays.stream(hits.getHits()).map(hit -> { String sourceAsString = hit.getSourceAsString(); SkuEsModelTo model = JSON.parseObject(sourceAsString, SkuEsModelTo.class); //高亮 if (StringUtils.isNotEmpty(param.getKeyword())) { Map<String, HighlightField> highlightFields = hit.getHighlightFields(); HighlightField highlightField = highlightFields.get("skuTitle"); String highLight = highlightField.getFragments()[0].string(); System.out.println("highlightFields" + highlightField.getFragments()[0]); model.setSkuTitle(highLight); } return model; }).collect(Collectors.toList()); result.setProducts(skuEsModelTos); /** * 聚合分析结果 */ Aggregations aggregations = response.getAggregations(); //2.当前命中结果聚合分析出来的所有品牌信息 ParsedLongTerms brand_agg = aggregations.get("brand_agg"); List<SearchResult.BrandVo> brandVos = brand_agg.getBuckets().stream().map(bucket -> { SearchResult.BrandVo brandVo = new SearchResult.BrandVo(); Long brandId = bucket.getKeyAsNumber().longValue(); ParsedStringTerms brand_img_agg = bucket.getAggregations().get("brand_img_agg"); ParsedStringTerms brand_name_agg = bucket.getAggregations().get("brand_name_agg"); String brandImg = brand_img_agg.getBuckets().get(0).getKeyAsString(); String brandName = brand_name_agg.getBuckets().get(0).getKeyAsString(); brandVo.setBrandId(brandId); brandVo.setBrandName(brandName); brandVo.setBrandImg(brandImg); return brandVo; }).collect(Collectors.toList()); result.setBrands(brandVos); //3.当前所有商品涉及到的所有分类信息 ParsedLongTerms catelog_agg = aggregations.get("catelog_agg"); List<SearchResult.CatalogVo> catalogVos = catelog_agg.getBuckets().stream().map(bucket -> { SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo(); long catelogId = bucket.getKeyAsNumber().longValue(); ParsedStringTerms catelog_name_agg = bucket.getAggregations().get("catelog_name_agg"); String catelogName = catelog_name_agg.getBuckets().get(0).getKeyAsString(); catalogVo.setCatelogName(catelogName); catalogVo.setCatelogId(catelogId); return catalogVo; }).collect(Collectors.toList()); result.setCatalogs(catalogVos); //4.当前所有商品涉及到的所有属性信息 ParsedNested attr_agg = aggregations.get("attr_agg"); ParsedLongTerms attr_id_agg = attr_agg.getAggregations().get("attr_id_agg"); List<SearchResult.AttrVo> attrVos = attr_id_agg.getBuckets().stream().map(bucket -> { SearchResult.AttrVo attrVo = new SearchResult.AttrVo(); //4.1 获取属性id long attrId = bucket.getKeyAsNumber().longValue(); //4.2 获取属性名字和值 ParsedStringTerms attr_name_agg = bucket.getAggregations().get("attr_name_agg"); ParsedStringTerms attr_value_agg = bucket.getAggregations().get("attr_value_agg"); String attrName = attr_name_agg.getBuckets().get(0).getKeyAsString(); List<String> attrValues = attr_value_agg.getBuckets().stream() .map(value -> value.getKeyAsString()).collect(Collectors.toList()); attrVo.setAttrId(attrId); attrVo.setAttrName(attrName); attrVo.setAttrValue(attrValues); return attrVo; }).collect(Collectors.toList()); result.setAttrs(attrVos); return result; }}