1. @Service("SearchServiceImpl")
    2. public class SearchServiceImpl implements MallSearchService {
    3. @Autowired
    4. private RestHighLevelClient restHighLevelClient;
    5. @Override
    6. public SearchResult search(SearchParam searchParam) {
    7. SearchResult result = null;
    8. //1.检索请求
    9. SearchRequest searchRequest = buildSearchRequest(searchParam);
    10. try {
    11. //2.执行请求
    12. SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    13. //3.分析响应数据, 封装成我们需要的格式
    14. result = buildSearchResult(response, searchParam);
    15. } catch (IOException e) {
    16. e.printStackTrace();
    17. }
    18. return result;
    19. }
    20. private SearchRequest buildSearchRequest(SearchParam param) {
    21. //1.指定DSL检索条件, 构建查询语句
    22. SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    23. BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    24. /* 查询: 模糊匹配, 过滤(按照属性/分类/品牌/价格区间/库存) */
    25. //1.1 must-skuTitle
    26. if (StringUtils.isNotEmpty(param.getKeyword())) {
    27. boolQuery.must(QueryBuilders.termQuery("skuTitle", param.getKeyword()));
    28. }
    29. //1.2 filter过滤查询
    30. if (param.getCatalog3Id() != null) {
    31. boolQuery.filter(QueryBuilders.termQuery("catelogId", param.getCatalog3Id()));
    32. }
    33. if (param.getBrandId() != null && param.getBrandId().size() > 0) {
    34. TermsQueryBuilder termsQuery = QueryBuilders.termsQuery("brandId", param.getBrandId());
    35. boolQuery.filter(termsQuery);
    36. }
    37. if (param.getAttrs() != null && param.getAttrs().size() > 0) {
    38. for (String attr : param.getAttrs()) {
    39. BoolQueryBuilder nestedBoolQuery = QueryBuilders.boolQuery();
    40. //attrs=1_a13:b14&attrs=2_2018:2019
    41. String[] s = attr.split("_");
    42. String attrId = s[0];
    43. String[] attrValues = s[1].split(":");
    44. nestedBoolQuery.must(QueryBuilders.termQuery("attrs.attrId", attrId));
    45. nestedBoolQuery.must(QueryBuilders.termsQuery("attrs.attrValue", attrValues));
    46. NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestedBoolQuery, ScoreMode.None);
    47. boolQuery.filter(nestedQuery);
    48. }
    49. }
    50. if (param.getHasStock() != null) {
    51. boolQuery.filter(QueryBuilders.termQuery("hasStock", param.getHasStock() == 1));
    52. }
    53. if (param.getSkuPrice() != null) {
    54. RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");
    55. //4000_6000/_6000/4000_
    56. String[] s = param.getSkuPrice().split("_");
    57. if (param.getSkuPrice().endsWith("_")) {
    58. rangeQuery.gte(s[0]);
    59. } else {
    60. rangeQuery.gte(s[0]).lte(s[1]);
    61. }
    62. boolQuery.filter(rangeQuery);
    63. }
    64. sourceBuilder.query(boolQuery);
    65. /* 排序, 分页, 高亮 */
    66. //2.1 排序 skuPrice_asc/desc
    67. if (StringUtils.isNotEmpty(param.getSort())) {
    68. String sort = param.getSort();
    69. String[] s = sort.split("_");
    70. SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
    71. sourceBuilder.sort(s[0], order);
    72. }
    73. //2.2 分页 pageSize: 5
    74. // pageNum:1 from:0 size:5 [0,1,2,3,4]
    75. // pageNum:2 from:5 size:5 [5,6,7,8,9]
    76. // from = (pageNum-1)*size
    77. sourceBuilder.from((param.getPageNum() - 1) * EsConstant.PRODUCT_PAGESIZE);
    78. sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);
    79. //2.3 高亮
    80. if (StringUtils.isNotEmpty(param.getKeyword())) {
    81. HighlightBuilder builder = new HighlightBuilder();
    82. builder.field("skuTitle");
    83. builder.preTags("<b style='color:red'>");
    84. builder.postTags("</b>");
    85. sourceBuilder.highlighter(builder);
    86. }
    87. /**
    88. * 聚合分析
    89. */
    90. //1.品牌聚合
    91. TermsAggregationBuilder brand_agg = AggregationBuilders.terms("brand_agg").field("brandId");
    92. TermsAggregationBuilder brand_name_agg = AggregationBuilders.terms("brand_name_agg").field("brandName").size(1);
    93. TermsAggregationBuilder brand_img_agg = AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1);
    94. brand_agg.subAggregation(brand_name_agg);
    95. brand_agg.subAggregation(brand_img_agg);
    96. sourceBuilder.aggregation(brand_agg);
    97. //2.分类聚合
    98. TermsAggregationBuilder catelog_agg = AggregationBuilders.terms("catelog_agg").field("catelogId");
    99. TermsAggregationBuilder catelog_name_agg = AggregationBuilders.terms("catelog_name_agg").field("catelogName").size(1);
    100. catelog_agg.subAggregation(catelog_name_agg);
    101. sourceBuilder.aggregation(catelog_agg);
    102. //3.属性聚合
    103. NestedAggregationBuilder attr_agg = AggregationBuilders.nested("attr_agg", "attrs");
    104. TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
    105. TermsAggregationBuilder attr_name_agg = AggregationBuilders.terms("attr_name_agg").field("attrs.attrName");
    106. TermsAggregationBuilder attr_value_agg = AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue");
    107. attr_id_agg.subAggregation(attr_name_agg);
    108. attr_id_agg.subAggregation(attr_value_agg);
    109. attr_agg.subAggregation(attr_id_agg);
    110. sourceBuilder.aggregation(attr_agg);
    111. System.out.println("构造的DSL" + sourceBuilder.toString());
    112. return new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX}, sourceBuilder);
    113. }
    114. private SearchResult buildSearchResult(SearchResponse response, SearchParam param) {
    115. SearchResult result = new SearchResult();
    116. SearchHits hits = response.getHits();
    117. List<SkuEsModelTo> skuEsModelTos = Arrays.stream(hits.getHits()).map(hit -> {
    118. String sourceAsString = hit.getSourceAsString();
    119. SkuEsModelTo model = JSON.parseObject(sourceAsString, SkuEsModelTo.class);
    120. //高亮
    121. if (StringUtils.isNotEmpty(param.getKeyword())) {
    122. Map<String, HighlightField> highlightFields = hit.getHighlightFields();
    123. HighlightField highlightField = highlightFields.get("skuTitle");
    124. String highLight = highlightField.getFragments()[0].string();
    125. System.out.println("highlightFields" + highlightField.getFragments()[0]);
    126. model.setSkuTitle(highLight);
    127. }
    128. return model;
    129. }).collect(Collectors.toList());
    130. result.setProducts(skuEsModelTos);
    131. /**
    132. * 聚合分析结果
    133. */
    134. Aggregations aggregations = response.getAggregations();
    135. //2.当前命中结果聚合分析出来的所有品牌信息
    136. ParsedLongTerms brand_agg = aggregations.get("brand_agg");
    137. List<SearchResult.BrandVo> brandVos = brand_agg.getBuckets().stream().map(bucket -> {
    138. SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
    139. Long brandId = bucket.getKeyAsNumber().longValue();
    140. ParsedStringTerms brand_img_agg = bucket.getAggregations().get("brand_img_agg");
    141. ParsedStringTerms brand_name_agg = bucket.getAggregations().get("brand_name_agg");
    142. String brandImg = brand_img_agg.getBuckets().get(0).getKeyAsString();
    143. String brandName = brand_name_agg.getBuckets().get(0).getKeyAsString();
    144. brandVo.setBrandId(brandId);
    145. brandVo.setBrandName(brandName);
    146. brandVo.setBrandImg(brandImg);
    147. return brandVo;
    148. }).collect(Collectors.toList());
    149. result.setBrands(brandVos);
    150. //3.当前所有商品涉及到的所有分类信息
    151. ParsedLongTerms catelog_agg = aggregations.get("catelog_agg");
    152. List<SearchResult.CatalogVo> catalogVos = catelog_agg.getBuckets().stream().map(bucket -> {
    153. SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
    154. long catelogId = bucket.getKeyAsNumber().longValue();
    155. ParsedStringTerms catelog_name_agg = bucket.getAggregations().get("catelog_name_agg");
    156. String catelogName = catelog_name_agg.getBuckets().get(0).getKeyAsString();
    157. catalogVo.setCatelogName(catelogName);
    158. catalogVo.setCatelogId(catelogId);
    159. return catalogVo;
    160. }).collect(Collectors.toList());
    161. result.setCatalogs(catalogVos);
    162. //4.当前所有商品涉及到的所有属性信息
    163. ParsedNested attr_agg = aggregations.get("attr_agg");
    164. ParsedLongTerms attr_id_agg = attr_agg.getAggregations().get("attr_id_agg");
    165. List<SearchResult.AttrVo> attrVos = attr_id_agg.getBuckets().stream().map(bucket -> {
    166. SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
    167. //4.1 获取属性id
    168. long attrId = bucket.getKeyAsNumber().longValue();
    169. //4.2 获取属性名字和值
    170. ParsedStringTerms attr_name_agg = bucket.getAggregations().get("attr_name_agg");
    171. ParsedStringTerms attr_value_agg = bucket.getAggregations().get("attr_value_agg");
    172. String attrName = attr_name_agg.getBuckets().get(0).getKeyAsString();
    173. List<String> attrValues = attr_value_agg.getBuckets().stream()
    174. .map(value -> value.getKeyAsString()).collect(Collectors.toList());
    175. attrVo.setAttrId(attrId);
    176. attrVo.setAttrName(attrName);
    177. attrVo.setAttrValue(attrValues);
    178. return attrVo;
    179. }).collect(Collectors.toList());
    180. result.setAttrs(attrVos);
    181. return result;
    182. }
    183. }