基于Elasticsearch商品搜索(模仿某东搜索页面的简单实现)

前言:

本文章是基于Elasticsearch5.6.8进行的商品搜索(小声说话:6版本以后Elasticsearch大改,所用的API文档不相同,建议小伙伴去官网观看)

Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。

Elasticsearch是与名为Logstash的数据收集和日志解析引擎以及名为Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案,称为“Elastic Stack”(以前称为“ELK stack”)。

Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。”Elasticsearch是分布式的,这意味着索引可以被分成分片,每个分片可以有0个或多个副本。每个节点托管一个或多个分片,并充当协调器将操作委托给正确的分片。再平衡和路由是自动完成的。“相关数据通常存储在同一个索引中,该索引由一个或多个主分片和零个或多个复制分片组成。一旦创建了索引,就不能更改主分片的数量。

Elasticsearch使用Lucene,并试图通过JSON和Java API提供其所有特性。它支持facetting和percolating,如果新文档与注册查询匹配,这对于通知非常有用。另一个特性称为“网关”,处理索引的长期持久性;例如,在服务器崩溃的情况下,可以从网关恢复索引。Elasticsearch支持实时GET请求,适合作为NoSQL数据存储,但缺少分布式事务。(以上哔哔哔的话来源百度百科)

需求:

模仿某东页面,简单的实现:

搜索关键字查询
品牌过滤查询
品牌聚合查询
规格过滤查询
规格聚合查询
价格区间查询
分页查询
排序查询
高亮查询
图片来源于网络,如有侵权,请联系我删除!

分析

用Map集合接收客户端传递的参数,在用Map集合返回数据到客户端(用Map集合应该没人反对吧,手动狗头保命)!

搜索关键字查询
    @GetMapping
    @ResponseBody
    public Map search(@RequestParam Map<String, String> searchMap) {
        if (null != searchMap) {
            //对搜索入参带有特殊符号进行处理
            //获取map中每个键值对集合
            Set<Map.Entry<String, String>> entries = searchMap.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                //如果键值对中的key是以spec_开头
                if (entry.getKey().startsWith("spec_")) {
                    searchMap.put(entry.getKey(), entry.getValue().replace("+", "%2B"));
                }
            }
        }
        return searchService.search(searchMap);
    }

业务代码:

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件
            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }
            nativeSearchQueryBuilder.withQuery(boolQuery);
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();  
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent()); 
        }
        return resultMap;
    }
}

总结:在controller层 对传递的参数进行特殊符号的处理(虽然现在的浏览器会自动转码)

品牌过滤查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            nativeSearchQueryBuilder.withQuery(boolQuery);

            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            
        }
        return resultMap;
    }
}
品牌聚合查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
        }
        return resultMap;
    }
}
规格过滤查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
        }
        return resultMap;
    }
}
规格聚合查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}

总结:
规格聚合查询时,List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());返回的是List<String>,在前端拿到数据的时候没有去处重复元素,会导致数据的不安全性,同时也为难前端的小姐姐从List集合取出数据展示。
所以我补充了一个formartSpec方法将list<String>------>Map<String Set<String>>

价格区间查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            //按照价格过滤
            if (!StringUtils.isEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                if (prices.length == 2) {
                    //boolQuery.filter过滤查询,termQuery代表精确查询,lte代表小于等于
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                //boolQuery.filter过滤查询,termQuery代表精确查询,gte代表大于等于
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}

分页查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            //按照价格过滤
            if (!StringUtils.isEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                if (prices.length == 2) {
                    //boolQuery.filter过滤查询,termQuery代表精确查询,lte代表小于等于
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                //boolQuery.filter过滤查询,termQuery代表精确查询,gte代表大于等于
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            //分页查询
            String pageNum = searchMap.get("PageNum");//当前页
            String pageSize = searchMap.get("PageSize");// 每页数据条数
            if (StringUtils.isEmpty(searchMap.get("PageNum"))) {
                pageNum = PAGE_NUM;
            }
            if (StringUtils.isEmpty(searchMap.get("PageSize"))) {
                pageSize = PAGE_SIZE;
            }
            //设置分页
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Integer.parseInt(pageSize)));

            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}
排序查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            //按照价格过滤
            if (!StringUtils.isEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                if (prices.length == 2) {
                    //boolQuery.filter过滤查询,termQuery代表精确查询,lte代表小于等于
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                //boolQuery.filter过滤查询,termQuery代表精确查询,gte代表大于等于
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            //分页查询
            String pageNum = searchMap.get("PageNum");//当前页
            String pageSize = searchMap.get("PageSize");// 每页数据条数
            if (StringUtils.isEmpty(searchMap.get("PageNum"))) {
                pageNum = PAGE_NUM;
            }
            if (StringUtils.isEmpty(searchMap.get("PageSize"))) {
                pageSize = PAGE_SIZE;
            }
            //设置分页
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Integer.parseInt(pageSize)));

             //排序
            if (StringUtils.isNotEmpty(searchMap.get("sortField")) && StringUtils.isNotEmpty(searchMap.get("sortRule"))) {
                if ("ASC".equals(searchMap.get("sortRule"))) {
                    //升序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.ASC));
                } else {
                    //降序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.DESC));
                }
            }
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}
高亮查询
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            //按照价格过滤
            if (!StringUtils.isEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                if (prices.length == 2) {
                    //boolQuery.filter过滤查询,termQuery代表精确查询,lte代表小于等于
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                //boolQuery.filter过滤查询,termQuery代表精确查询,gte代表大于等于
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            //分页查询
            String pageNum = searchMap.get("PageNum");//当前页
            String pageSize = searchMap.get("PageSize");// 每页数据条数
            if (StringUtils.isEmpty(searchMap.get("PageNum"))) {
                pageNum = PAGE_NUM;
            }
            if (StringUtils.isEmpty(searchMap.get("PageSize"))) {
                pageSize = PAGE_SIZE;
            }
            //设置分页
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Integer.parseInt(pageSize)));

             //排序
            if (StringUtils.isNotEmpty(searchMap.get("sortField")) && StringUtils.isNotEmpty(searchMap.get("sortRule"))) {
                if ("ASC".equals(searchMap.get("sortRule"))) {
                    //升序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.ASC));
                } else {
                    //降序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.DESC));
                }
            }
            
             //高亮
            HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
            nativeSearchQueryBuilder.withHighlightFields(field);
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            
                            //设置高亮
                            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                            if (null != highlightFields && highlightFields.size() > 0) {
                                skuinfo.setName(highlightFields.get("name").getFragments()[0].toString());
                            }
                            
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}
最终代码如下:
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //设置每页分页查询的数据
    public final static String PAGE_SIZE = "20";
    //设置默认当前页
    public final static String PAGE_NUM = "1";

    
    public Map search(Map<String, String> searchMap) {
        //返回数据集合
        HashMap<String, Object> resultMap = new HashMap<>();
        
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //用boolQuery 拼接若干个查询条件

            //按照关键字查询
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
                //boolQuery.must去拼接查询条件,matchQuery代表模糊查询 匹配查询。添加查询的字段和值,并且通过operator指定and
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌过滤查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                //boolQuery.filter过滤查询,termQuery代表精确查询
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格过滤查询
            Set<String> keySet = searchMap.keySet();
            for (String key : keySet) {
                //如果key中包括spec_
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //boolQuery.filter过滤查询,termQuery代表精确查询
                    boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            
            //按照价格过滤
            if (!StringUtils.isEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                if (prices.length == 2) {
                    //boolQuery.filter过滤查询,termQuery代表精确查询,lte代表小于等于
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                //boolQuery.filter过滤查询,termQuery代表精确查询,gte代表大于等于
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            
            nativeSearchQueryBuilder.withQuery(boolQuery);

             //品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            
            //规格聚合(分组)查询
            String skuSpec = "skuSpec";
            //addAggregation代表聚合,terms设置聚合查询的列名,field设置对那个域操作
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            
            //分页查询
            String pageNum = searchMap.get("PageNum");//当前页
            String pageSize = searchMap.get("PageSize");// 每页数据条数
            if (StringUtils.isEmpty(searchMap.get("PageNum"))) {
                pageNum = PAGE_NUM;
            }
            if (StringUtils.isEmpty(searchMap.get("PageSize"))) {
                pageSize = PAGE_SIZE;
            }
            //设置分页
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Integer.parseInt(pageSize)));

             //排序
            if (StringUtils.isNotEmpty(searchMap.get("sortField")) && StringUtils.isNotEmpty(searchMap.get("sortRule"))) {
                if ("ASC".equals(searchMap.get("sortRule"))) {
                    //升序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.ASC));
                } else {
                    //降序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.DESC));
                }
            }
            
             //高亮
            HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
            nativeSearchQueryBuilder.withHighlightFields(field);
            
            /**
             * @param nativeSearchQueryBuilder.build() 条件对象
             * @param Skuinfo.class 查询的实体类
             * @param SearchResultMapper()  查询结果操作对象
             */
            AggregatedPage<Skuinfo> resultinfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), Skuinfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    ArrayList<T> list = new ArrayList<>();
                    
                    //查询操作
                    SearchHits hits = searchResponse.getHits();
                    if (hits != null) {
                        for (SearchHit hit : hits) {
                            //hit转成skuinfo
                            Skuinfo skuinfo = JSON.parseObject(hit.getSourceAsString(), Skuinfo.class);
                            
                            //设置高亮
                            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                            if (null != highlightFields && highlightFields.size() > 0) {
                                skuinfo.setName(highlightFields.get("name").getFragments()[0].toString());
                            }
                            
                            list.add((T) skuinfo);
                        }
                    }
                    // list数据集合  pageable页对象   hits.getTotalHits()总记录数  searchResponse.getAggregations()
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //封装查询结果
            //总条数
            resultMap.put("total", resultinfo.getTotalElements());
            //总页数
            resultMap.put("totalPages", resultinfo.getTotalPages());
            //封装当前页
            resultMap.put("pageNum", pageNum);
            //结果集合
            resultMap.put("rows", resultinfo.getContent());
            //品牌聚合结果
            StringTerms brandTerms = (StringTerms) resultinfo.getAggregation(skuBrand);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
             //规格聚合结果
            StringTerms skuSpecTerms = (StringTerms) resultinfo.getAggregation(skuSpec);
            List<String> skuSpecList = skuSpecTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            //封装规格
            resultMap.put("skuSpecList", this.formartSpec(skuSpecList));
            
            
        }
        return resultMap;
    }


    /**
     * @param skuSpecList
     * @return java.util.Map<java.lang.String, java.util.Set < java.lang.String>>
     * @description: 将list<String>------>Map<String Set<String>>
     * @author 大佬味的小男孩
     * @date 2020/07/27 15:15
     */
    public Map<String, Set<String>> formartSpec(List<String> skuSpecList) {
        HashMap<String, Set<String>> resultMap = new HashMap<>();

        if (skuSpecList != null && skuSpecList.size() > 0) {
            //得到集合中每个json数据
            for (String jsonString : skuSpecList) {
                //将jsonString转成map
                Map<String, String> specMap = JSON.parseObject(jsonString, Map.class);
                //遍历map集合
                for (String key : specMap.keySet()) {
                    //判断这个key在resultMap有没有specSet的map集合
                    Set<String> specSet = resultMap.get(key);
                    if (specSet == null) {
                        specSet = new HashSet<>();
                    }
                    specSet.add(specMap.get(key));
                    //将specMap中的键值对存入resultMap
                    resultMap.put(key, specSet);
                }
            }
        }
        return resultMap;
    }
}

今天这一篇都是业务逻辑代码,确实有点枯燥无味。

第三次来到简书,如果不理解,欢迎在评论交流!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352