import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;


@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;


//前端传递查询条件,将查询条件封装成map集合,多个条件构成map
    //返回的数据类型也是map,需要返回查询的结果,总条数之类的
    @Override
    public Map<String, Object> search(Map<String, String> searchmap) {
        //先读取到查询条件的关键字
        String keywords = searchmap.get("keywords");
        //判断关键字是否为空,不为空时再处理,为空赋初值
        if (StringUtils.isEmpty(keywords)){
            keywords = "手机";
        }

        //然后就是在es中搜索

        //1. 创建查询对象的构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //2. 设置查询条件,设置前端传递的查询条件和当前实体类中的那个属性匹配查询。
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", keywords));

        //分组查询    terms("categoryGroup")是设置分组后的名字,相当于map中设置了一个键。
        //           .field("category.keyword")是匹配实体类中的要分组的字段。keyword是精确匹配
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("categoryGroup").field("category.keyword"));

        //3. 创建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        //4. 使用es查询,查询到的所有数据都在searchHits对象中
        SearchHits<SkuInfo> searchHits = elasticsearchRestTemplate.search(query, SkuInfo.class);

        //创建一个集合用于存放分组查询的分组信息的数据
        //注:根据电视进行分词查询后可以将所有查询到的结果中的分组的字段获取出来存放进此list,所以就对应所有的数据的分类
        List<Object> categoryList = new ArrayList<>();
        //获取分组查询结果
        Terms terms = searchHits.getAggregations().get("categoryGroup");
        for (Terms.Bucket bucket : terms.getBuckets()) {
            categoryList.add(bucket.getKey());
        }

        //遍历查询结果,获取到所有查询到的数据
        List<SkuInfo> skuInfoList = new ArrayList<>();
        for (SearchHit<SkuInfo> searchHit : searchHits.getSearchHits()) {
            SkuInfo skuInfo = searchHit.getContent();
            //将查询到的skuInfo对象都存进list数组
            skuInfoList.add(skuInfo);
        }

        //map中存放查到的数据的list和总条数
        Map<String, Object> map = new HashMap<>();
        map.put("data", skuInfoList);
        map.put("dataCount", searchHits.getTotalHits());
        map.put("categoryList", categoryList);
        return map;
    }

        //map中存放查到的数据的list和总条数
        Map<String, Object> map = new HashMap<>();
        map.put("data", skuInfoList);
        map.put("dataCount", searchHits.getTotalHits());
        return map;
    }
  1. 注意
    在这里插入图片描述
    要注意查询条件和要查询的es中的数据中的属性相匹配,具体是要查询对应数据中的那个字段

在这里插入图片描述
在使用es查询两个参数分别是上边查询条件匹配后的查询对象和查询数据对应的实体类的字节码对象

在这里插入图片描述
这四步就是将查询条件导入进去然后获取查询结果。

在这里插入图片描述
这就是设置了一下,将所有条件搜索查询到的结果的数据的分类查询出来存进一个list

总结
es 查询和mybatisplus中的QueryWrapper设置条件的步骤和格式很像。mybatisplus条件查询也是先创建一个QueryWrapper对象,然后eq或like方法设置查询条件和对应要查询的实体类的字段。然后调用持久层的查询方法,将QueryWrapper对象传递进去。

补充,添加了排序,分页,条件查询等

//前端传递查询条件,将查询条件封装成map集合,多个条件构成map
    //返回的数据类型也是map,需要返回查询的结果,总条数之类的
    @Override
    public Map<String, Object> search(Map<String, String> searchmap) {
        //先读取到查询条件的关键字
        String keywords = searchmap.get("keywords");
        //判断关键字是否为空,不为空时再处理,为空赋初值
        if (StringUtils.isEmpty(keywords)) {
            keywords = "";
        }

        //然后就是在es中搜索
        //1. 创建查询对象的构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        //2. 设置查询条件,设置前端传递的查询条件和当前实体类中的那个属性匹配查询。
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", keywords));


        /*下边的分组查询就是可以获取到搜索出来的数据的一些分类,规格,品牌的统计,并不会按照输入的进行匹配查询*/
        //分类的分组查询    terms("categoryGroup")是设置分组后的名字,相当于map中设置了一个键。
        //           .field("category.keyword")是匹配实体类中的要分组的字段。keyword是精确匹配
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("categoryGroup").field("category.keyword"));

        //品牌的分组查询
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("brandGroup").field("brand.keyword"));

        //规格的分组查询
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("specGroup").field("spec.keyword"));


        /*多条件查询就是根据用户输入的数据进行匹配查询,和上边的分组查询不同,分组查询是做统计,这个是匹配用户的查询条件输出对应数据*/
        //多条件查询,即条件筛选,多条件查询时,matchQuery是自动分词查询的
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //判断条件是否为空
        if (!StringUtils.isEmpty(searchmap.get("brand"))) {
            //matchQuery的第一个参数是需要匹配的es中存入的数据字段,第二个是传递进来要匹配的字段
            boolQueryBuilder.filter(QueryBuilders.matchQuery("brand", searchmap.get("brand")));
        }
        if (!StringUtils.isEmpty(searchmap.get("category"))) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("category", searchmap.get("category")));
        }

        //规格的多条件查询,规格因为是"{\"机身内存\":\"16G\",\"网络\":\"联通4G\"}"这种格式,所以需要和其他字段区别开使用的查询方法不同
        for (String key : searchmap.keySet()) {   //前端传递进来的规格的键包括前缀spec_所以判断有包含的就是规格的
            if (key.startsWith("spec_")){
                //该方法两个参数分别是,第一个是匹配es中存入的数据的键,第二个是要进行查询的值,前端传递的查询条件
                boolQueryBuilder.filter(QueryBuilders.termQuery("specMap."+key.substring(key.indexOf("_")+1)+".keyword", searchmap.get(key)));
            }
        }

        //价格的多条件查询,先判断价格是否为空,不为空再转成double类型
        String price = searchmap.get("price");
        //价格的格式有¥-price,maxPrice-minPrice,minPrice-maxPrice,price-¥
        if (!StringUtils.isEmpty(price)){
            //将价格前后两部分切分出来
            String[] split = price.split("-");
            if ("¥".equals(split[0])) {
                //rangeQuery的方法就是判断区间的
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(Double.parseDouble(split[1])));
            }else if ("¥".equals(split[1])){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(Double.parseDouble(split[0])));
            }else {
                //对大小值进行调换
                double minPrice = Double.parseDouble(split[0]);
                double maxPrice = Double.parseDouble(split[1]);
                if (minPrice >maxPrice){
                    double c = maxPrice;
                    maxPrice = minPrice;
                    minPrice = c;
                }
                //from -- to from是从小的to到大的
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(minPrice).to(maxPrice));
            }
        }

        //最后还需要把设置的条件查询的条件加入到构建对象中,进行接下来的查询对象的创建才会有结果
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        //多条件查询结束


        //分页查询
        String currentPage = searchmap.get("currentPage");
        if (StringUtils.isEmpty(currentPage)){
            currentPage = "1";
        }
        int page = Integer.parseInt(currentPage);
        //PageRequest.of的两个参数是当前页和每页显示的条数
        nativeSearchQueryBuilder.withPageable(PageRequest.of(page, 10));
        //分页查询结束


        //排序
        //sortFild是按照哪个字段进行排序
        String sortField = searchmap.get("sortField");
        //sortRule是排序规格,转成小写
        String sortRule = searchmap.get("sortRule");
        System.out.println(sortRule);
        if (!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)) {
            sortRule = sortRule.toLowerCase();
            //.fieldSorts是判断按照哪个字段进行排序,order是传递一个排序的规则
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order("asc".equals(sortRule)? SortOrder.ASC:SortOrder.DESC));
        }
        //排序结束


        //3. 创建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        //4. 使用es查询,查询到的所有数据都在searchHits对象中
        SearchHits<SkuInfo> searchHits = elasticsearchRestTemplate.search(query, SkuInfo.class);

        //5. 处理分页结果
        SearchPage<SkuInfo> pageHits = SearchHitSupport.searchPageFor(searchHits, query.getPageable());


        //返回分页的总页数
        int pageCount = pageHits.getTotalPages();

        //获取分类的分组查询结果,es的查询结果集中放着所有的查询数据
        Terms categoryTerms = searchHits.getAggregations().get("categoryGroup");
        //创建一个集合用于存放分组查询的分组信息的数据
        //注:根据电视进行分词查询后可以将所有查询到的结果中的分组的字段获取出来存放进此list,所以就对应所有的数据的分类
        List<Object> categoryList = addGroup(categoryTerms);

        //获取品牌的分类结果
        Terms brandTerms = searchHits.getAggregations().get("brandGroup");
        List<Object> brandList = this.addGroup(brandTerms);

        //获取规格的分类结果
        Terms specTerms = searchHits.getAggregations().get("specGroup");
        List<Object> specList = this.addGroup(specTerms);   //"{\"机身内存\":\"16G\",\"网络\":\"联通4G\"}",
        Map<String, Set<String>> specMap = getSpecMap(specList);


        //遍历查询结果,获取到所有查询到的数据
        List<SkuInfo> skuInfoList = new ArrayList<>();
        for (SearchHit<SkuInfo> searchHit : searchHits.getSearchHits()) {
            SkuInfo skuInfo = searchHit.getContent();
            //将查询到的skuInfo对象都存进list数组
            skuInfoList.add(skuInfo);
        }



        //map中存放查到的数据的list和总条数
        Map<String, Object> map = new HashMap<>();
        map.put("data", skuInfoList);   //查询到的数据
        map.put("dataCount", searchHits.getTotalHits());   //数据总条数
        map.put("categoryList", categoryList);  //商品分类
        map.put("brandList", brandList);  //品牌
        map.put("specMap", specMap);   //规格
        map.put("pageCount", pageCount);   //总页数
        return map;
    }

    //此方法是通过传递进来查询到商品的规格,然后将规格处理统计后返回
    private Map<String, Set<String>> getSpecMap(List<Object> specList) {
        //需要将所有的规格转成map,而且值还要去掉重复
        Map<String, Set<String>> specMap = new HashMap<>();
        for (Object spec : specList) {
            //先将所有的规格信息转成json类型的字符创
            //再将每个规格转成map
            Map<String, String> map = JSON.parseObject(spec.toString(), Map.class);
            //读取到所有键
            Set<String> set = map.keySet();
            //根据键获取值
            for (String o : set) {  //o -> 网络
                //这是map每个键对应的值
                String s = map.get(o);  //  s -> 16G

                //如果specmap中存在o这个键,那么直接加入到o对应的值中,没有就创建set集合
                Set<String> specSet = specMap.get(o);
                //第一次循环的时候,specMap中没有键和值,所以需要创建set集合
                if (CollectionUtils.isEmpty(specSet)) {
                    specSet = new HashSet<>();
                }
                specSet.add(s);
                specMap.put(o, specSet);
            }
        }
        return specMap;
    }

    /**
     * @param terms 是传递进来一个分组的查询结果
     * @return 将传递进来的结果进行处理后装入list集合返回
     */
    private List<Object> addGroup(Terms terms) {
        List<Object> categoryList = new ArrayList<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            categoryList.add(bucket.getKey());
        }
        return categoryList;
    }
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐