原创

Java操作ES的基本使用


/**
 * @author L
 * ES 操作
 */
@Service
public class SkuServiceImpl implements SkuService {
    @Autowired
    SkuFeign skuFeign;
    @Autowired
    SkuRepository skuRepository;
    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 搜索
     * @param queryMap
     * @return
     */
    @Override
    public Map<String, Object> search(Map<String, String> queryMap) {
        //搜索构建条件
        NativeSearchQueryBuilder builder = buildBasicQuery(queryMap);

        //搜索 并且封装相应的数据类型
        Map<String, Object> resultMap = searchList(builder);

/*        //如果用户没有选择分类,将所有分类查询出来 否则不再进行查询
        if (queryMap == null || StringUtils.isBlank(queryMap.get("category"))) {
            //根据关键字 将分类 进行分组查询(查询分类集合)
            List<String> categoryList = searchCategoryList(builder);
            resultMap.put("categoryList", categoryList);
        }

        //如果没有选择品牌,就将品牌列表查询出,反之不查
        if (queryMap == null || StringUtils.isBlank(queryMap.get("brand"))) {
            //根据关键字 将品牌 进行分组查询(查询品牌集合)
            List<String> brandList = searchBrandList(builder);
            resultMap.put("brandList", brandList);
        }

        //根据关键字 将规格信息 进行分组查询(查询规格信息)
        Map<String, Set<String>> specMap = searchSpecList(builder);
        resultMap.put("specList", specMap);*/

        //分组搜索品牌、分类、规格查询
        Map<String, Object> groupMap = searchGroupList(builder, queryMap);
        resultMap.putAll(groupMap);
        return resultMap;
    }

    /**
     * 搜索条件封装
     * @param queryMap
     * @return
     */
    private NativeSearchQueryBuilder buildBasicQuery(Map<String, String> queryMap) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //组合条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //条件拼接
        if (!queryMap.isEmpty()) {
            String keywords = queryMap.get("keywords");
            if (StringUtils.isNotBlank(keywords)) {
                //builder.withQuery(QueryBuilders.queryStringQuery(keywords).field("name"));
                //在name域中 模糊匹配包含keyword的数据
                boolQuery.must(QueryBuilders.queryStringQuery(keywords).field("name"));
            }

            //品牌过滤
            String brand = queryMap.get("brand");
            if (StringUtils.isNotBlank(brand)) {
                boolQuery.must(QueryBuilders.termQuery("brandName", brand));
            }

            //分类过滤
            String category = queryMap.get("category");
            if (StringUtils.isNotBlank(category)) {
                //精确匹配
                boolQuery.must(QueryBuilders.termQuery("categoryName", category));
            }

            //规格过滤 key以 'spec_' 开头的都为规格查询条件
            queryMap.entrySet().stream().filter(item -> item.getKey().startsWith("spec_")).forEach(item -> {
                boolQuery.must(QueryBuilders.termQuery("specMap." + item.getKey().substring(5) + ".keyword", item.getValue()));
            });

            //价格区间过滤
            String price = queryMap.get("price");
            if (StringUtils.isNotBlank(price)) {
                if (price.contains("元")) {
                    //将中文剔除
                    price = price.substring(0, price.lastIndexOf("元"));
                    String[] scope = price.split("-");
                    if (scope != null && scope.length > 0) {
                        //起始价格
                        boolQuery.must(QueryBuilders.rangeQuery("price").gte(Integer.parseInt(scope[0])));
                        //截止价格
                        if (scope.length > 1) {
                            boolQuery.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(scope[1])));
                        }
                    }
                }
            }
        }
        //分页处理
        Integer page = conversionPage(queryMap);
        Integer size = 3;//每页展示的条数
        builder.withPageable(PageRequest.of(page - 1, size));
        builder.withQuery(boolQuery);

        //排序处理
        String sortField = queryMap.get("sortField");//排序的域
        String sortRule = queryMap.get("sortRule");//排序规则
        if (StringUtils.isNotBlank(sortField) && StringUtils.isNotBlank(sortRule)){
            //排序
            builder.withSort(new FieldSortBuilder(sortField).order(SortOrder.valueOf(sortRule)));
        }
        return builder;
    }

    //页数处理
    private Integer conversionPage(Map<String, String> queryMap) {
        if (queryMap != null) {
            String pageNum = queryMap.get("pageNum");
            if (StringUtils.isNotBlank(pageNum)) {
                try {
                    int page = Integer.parseInt(pageNum);
                    //防止为0
                    return page <= 0 ? 1 :page;
                } catch (NumberFormatException e) {
                    return 1;
                }
            }
        }
        //默认第一页
        return 1;
    }

    /**
     * 集合搜索
     * @param builder
     * @return
     */
    private Map<String, Object> searchList(NativeSearchQueryBuilder builder) {
        //添加高亮处理
        HighlightBuilder.Field field = new HighlightBuilder.Field("name");//指定高亮的域
        field.preTags("<em style='color:red;'>");//前缀
        field.postTags("</em>");//后缀
        field.fragmentSize(100);//碎片长度
        builder.withHighlightFields(field);

        /**
         * 查询
         * param1: 条件对象
         * param2: 返回的对象实体
         * return: 结果集的封装
         */
        //AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class); 普通搜索

        //高亮搜索 SearchResultMapper
        AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                List<T> skuInfoList = new ArrayList<T>();
                //获取所有数据 遍历 进行处理
                for (SearchHit hit : response.getHits()) {
                    SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);//非高亮数据
                    HighlightField name = hit.getHighlightFields().get("name");//获取name域的高亮数据
                    if (name != null && name.getFragments() != null){
                        Text[] content = name.getFragments();//取出高亮数据
                        skuInfo.setName(Arrays.toString(content));//替换
                        skuInfoList.add((T) skuInfo);//添加到返回的数据集合中
                    }else {
                        skuInfoList.add((T) skuInfo);
                    }
                }
                /**
                 * AggregatedPageImpl() 构造参数
                 * 1-》查询的数据集合
                 * 2-》分页参数
                 * 3-》总记录数
                 */
                return new AggregatedPageImpl<T>(skuInfoList,pageable,response.getHits().getTotalHits());
            }
        });
        List<SkuInfo> skuInfoList = page.getContent();
        //分页参数
        long total = page.getTotalElements();//总记录数
        int pageSize = page.getTotalPages();//总页数
        //封装返回对象
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("rows", skuInfoList);
        resultMap.put("total", total);
        resultMap.put("totalPages", pageSize);
        return resultMap;
    }

    /**
     * 分组查询 品牌、分类、规格等相关信息
     * @param builder
     * @return
     */
    private Map<String,Object> searchGroupList(NativeSearchQueryBuilder builder,Map<String,String> queryMap) {
        Map<String,Object> resultMap = new HashMap<>();
        //添加聚合操作
        String category = queryMap.get("category");
        if (queryMap == null ||StringUtils.isBlank(category)){
            builder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));//分类
        }
        String brand = queryMap.get("brand");
        if (queryMap == null || StringUtils.isBlank(brand)){
            builder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));//品牌
        }
        builder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(10000));//规格
        AggregatedPage<SkuInfo> agg = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);

        if (queryMap == null ||StringUtils.isBlank(brand)){
            List<String> brandList = strToList(agg.getAggregations().get("skuBrand"));//品牌信息
            resultMap.put("brandList",brandList);
        }
        if (queryMap == null ||StringUtils.isBlank(category)){
            List<String> categoryList = strToList(agg.getAggregations().get("skuCategory"));//分类信息
            resultMap.put("categoryList",categoryList);
        }

        List<String> specList = strToList(agg.getAggregations().get("skuSpec"));//规格信息
        //规格信息结构 Map<String,Set<String>> 如--》 内存(key): 4G 8G 16G(set)
        Map<String, Set<String>> specMap = new HashMap<>();
        specList.stream().forEach(item->{
            Map<String, String> spec = JSON.parseObject(item,Map.class);
            spec.entrySet().stream().forEach(entry -> {
                //获取原有的值
                Set<String> oldSet = specMap.get(entry.getKey());
                if (oldSet == null) {
                    oldSet = new HashSet<>();//第一次为null就实例一个新的set
                }
                oldSet.add(entry.getValue());//追加到原有的数据set中
                specMap.put(entry.getKey(), oldSet);//添加到specMap中
            });
        });
        resultMap.put("specList",specMap);
        return  resultMap;
    }

    private List<String> strToList(StringTerms stringTerms){
        return stringTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
    }


    /**
     * 根据关键字 将规格 进行分组查询(查询规格信息集合)
     * @param builder
     * @return 规格信息结构 Map<String,Set<String>> 如--》 内存(key): 4G 8G 16G(set)
     */
    /*private Map<String, Set<String>> searchSpecList(NativeSearchQueryBuilder builder) {
        //添加聚合(分组查询)操作
        builder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(10000));
        AggregatedPage<SkuInfo> agg = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
        //取出搜索的结果数据 getBuckets()
        StringTerms terms = agg.getAggregations().get("skuSpec");
        //规格信息结构 Map<String,Set<String>> 如--》 内存(key): 4G 8G 16G(set)
        Map<String, Set<String>> specMap = new HashMap<>();
        //合并所有的商品的规格参数
        terms.getBuckets().stream().forEach(bucket -> {
            String specStr = bucket.getKeyAsString();
            Map<String, String> spec = JSON.parseObject(specStr, Map.class);
            spec.entrySet().stream().forEach(entry -> {
                //获取原有的值
                Set<String> oldSet = specMap.get(entry.getKey());
                if (oldSet == null) {
                    oldSet = new HashSet<>();//第一次为null就实例一个新的set
                }
                oldSet.add(entry.getValue());//追加到原有的数据set中
                specMap.put(entry.getKey(), oldSet);//添加到specMap中
            });
        });
        return specMap;
    }*/

    /**
     * 根据关键字 将品牌 进行分组查询(查询品牌集合)
     * @param builder
     * @return
     */
    private List<String> searchBrandList(NativeSearchQueryBuilder builder) {
        //添加聚合(分组查询)操作
        builder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));
        AggregatedPage<SkuInfo> agg = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
        //取出搜索的结果数据 getBuckets()
        StringTerms terms = agg.getAggregations().get("skuBrand");
        List<String> brandList = new ArrayList<>();
        terms.getBuckets().stream().forEach(bucket -> brandList.add(bucket.getKeyAsString()));
        return brandList;
    }

    /**
     * 根据关键字 将分类 进行分组查询(查询分类集合)
     * @param builder
     * @return
     */
    private List<String> searchCategoryList(NativeSearchQueryBuilder builder) {
        //添加聚合操作
        builder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
        AggregatedPage<SkuInfo> agg = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
        //分组查询分类集合
        StringTerms stringTerms = agg.getAggregations().get("skuCategory");
        List<String> categoryList = new ArrayList<>();
        stringTerms.getBuckets().stream().forEach(bucket -> categoryList.add(bucket.getKeyAsString()));
        return categoryList;
    }

    /**
     * 数据的导入
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importData() {
        //1.查询出所有的Sku数据
        List<Sku> skuList = skuFeign.findAll().getData();
        //2.转换成与之对应的ES实体对象(SkuInfo)
        List<SkuInfo> skuInfoList = JSON.parseArray(JSON.toJSONString(skuList), SkuInfo.class);
        skuInfoList.stream().forEach(skuInfo -> skuInfo.setSpecMap(JSON.parseObject(skuInfo.getSpec(), Map.class)));
        //3.Dao
        skuRepository.saveAll(skuInfoList);
    }
}
Java

留言板