畅购项目个人笔记(elasticsearch搜索商品)

1构建搜索条件(NativeSearchQueryBuilder)

关键的类

  //构建搜索条件  用于封装各种搜索条件
    NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
      //过滤搜索// 模糊查询
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

  //高亮搜索
        HighlightBuilder.Field filed = new HighlightBuilder.Field("name");//高亮的域
   //高亮数据  和 非高亮数据 是不在一块的  替换  。。
        /**
         * 执行搜索相应结果给我
         * >1 搜索条件封装对象
         * >2 搜索的结果集(集合转化的对象)需要转化的类型
         * >3 AggregatedPage<SkuInfo> 返回结果集的封装
         */
 //高亮代码思路
 /**
     * 搜索条件封装
     */
    private NativeSearchQueryBuilder buildBaseQuery(Map<String, String> searchMap) {
        //构建搜索条件  用于封装各种搜索条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //过滤搜索// 模糊查询
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //根据关键词搜索
        if (searchMap != null & searchMap.size() > 0) {
            //根据关键词搜索
            String keywords = searchMap.get("keywords");
            //如果关键词不为空则搜索关键词数据
            if (!StringUtils.isEmpty(keywords)) {                                      //指定域名 name
                boolQueryBuilder.must(QueryBuilders.queryStringQuery(keywords).field("name"));
            }
            //搜索了分类  >category
            if (!StringUtils.isEmpty(searchMap.get("category"))) {                                      //指定域名 name
                boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", searchMap.get("category")));
            }
            //输入了品牌  >brand
            if (!StringUtils.isEmpty(searchMap.get("brand"))) {                                      //指定域名 name
                boolQueryBuilder.must(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }
            //规格过滤 条件搜索
            for (Map.Entry<String, String> entry : searchMap.entrySet()) {
                //判断searchMap中是否存在spec_开头的
                String key = entry.getKey();
                if (key.startsWith("spec_")) {
                    String value = entry.getValue();
                    boolQueryBuilder.must(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }
            String price = searchMap.get("price");
            if (!StringUtils.isEmpty(price)) {
                price = price.replace("元", "").replace("以上", "");
                //用-进行分割
                String[] prices = price.split("-");
                if (prices != null && prices.length > 0) {            //gt >       当有2个时候lte<
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.parseInt(prices[0])));
                    if (prices.length == 2) {
                        boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(prices[1])));
                    }
                }
            }
            //排序 实现
            String sortFiled = searchMap.get("sortFiled");//指定排序 的域
            String sortRule = searchMap.get("sortRule");   //指定排序的规则
            if (!StringUtils.isEmpty(sortFiled) && !StringUtils.isEmpty(sortRule)) {
                nativeSearchQueryBuilder.withSort(new FieldSortBuilder(sortFiled)  //指定域
                        .order(SortOrder.valueOf(sortRule)));  //排序规则

            }
        }
        //分页
        Integer pageNumber = converterPage(searchMap);
        Integer pageSize = 30;   //每页显示的数量
        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNumber, pageSize));
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

2.数据结果封装

 /**
     * 数据结果集封装
     *
     * @param nativeSearchQueryBuilder
     * @return
     */
    private HashMap<String, Object> searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder) {
        //高亮搜索
        HighlightBuilder.Field filed = new HighlightBuilder.Field("name");//高亮的域
        //前缀
        //<em style="color":red;">
        filed.preTags("<em style='color:red;'>");  //转义符

        //后缀  </em>
        filed.postTags("</em>");
        //碎片长度  关键词数据的长度
        filed.fragmentSize(100);  //100字符截取
        nativeSearchQueryBuilder.withHighlightFields(filed);
        //高亮数据  和 非高亮数据 是不在一块的  替换  。。
        /**
         * 执行搜索相应结果给我
         * >1 搜索条件封装对象
         * >2 搜索的结果集(集合转化的对象)需要转化的类型
         * >3 AggregatedPage<SkuInfo> 返回结果集的封装
         */
        //AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class);
        AggregatedPage<SkuInfo> page = elasticsearchTemplate.
                queryForPage(
                        nativeSearchQueryBuilder.build(),   //搜索条件封装
                        SkuInfo.class,//数据集合要转化的类型的字节码
                        //  SearchResultMapper);    //执行搜索后,将数据结果封装到该对象中
                        new SearchResultMapper() {
                            @Override
                            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                                //储存所以转换后的高亮对象
                                List<T> list = new ArrayList<>();

                                //执行查询,获取所有数据->结果集[非高亮数据][高亮数据]
                                for (SearchHit hit : response.getHits()) {
                                    //分析结果集数据,获取非高亮数据
                                    SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
                                    //分析结果集 获取高亮数据>只有某个域的高亮数据
                                    HighlightField highField = hit.getHighlightFields().get("name");
                                    if (highField != null && highField.getFragments() != null) {
                                        //高亮数据读取出来
                                        StringBuffer buffer = new StringBuffer();
                                        Text[] fragments = highField.getFragments();
                                        for (Text fragment : fragments) {
                                            buffer.append(fragment.toString());
                                        }
                                        //非高亮数据中 指定的域替换成高亮数据
                                        skuInfo.setName(buffer.toString());

                                    }

                                    //将高亮数据存入集合
                                    list.add((T) skuInfo);

                                }
                                return new AggregatedPageImpl<T>(list, pageable, response.getHits().getTotalHits());
                            }
                        });

//分页参数总记录数
        long totalElements = page.getTotalElements();
        //总页数
        int totalPages = page.getTotalPages();
        //获取数据返回集合
        List<SkuInfo> contents = page.getContent();
        //将数据添加到map  返回集合
        HashMap<String, Object> map = new HashMap<>();
        //分页数据
        map.put("rows", contents);
        map.put("total", totalElements);
        map.put("totalPages", totalPages);
        //获取搜索封装信息
        NativeSearchQuery query=nativeSearchQueryBuilder.build();
        Pageable pageable = query.getPageable();//获取分页信息
        int pageSize=pageable.getPageSize();
        int pageNumber = pageable.getPageNumber();//获取页码
        map.put("pageSize", pageSize);
        map.put("pageNumber", pageNumber);
        return map;
    }

3 分组进行模糊查询

  /**
     * 分组查询分类集合
     * 添加 一个聚合操作
     * 1 取别名   -------------   分类分组查询
     * 2根据那个域分组
     */
    private Map<String, Object> searchGroupList(NativeSearchQueryBuilder nativeSearchQueryBuilder, Map<String, String> searchMap) {
        /**
         * 分组查询分类集合
         * .addAggregation :添加 一个聚合操作 
         * 1) 取别名
         * 2) 表示根据某个域进行分组查询
         */
        //定义一个Map存储所有的分组数据
        Map<String, Object> groupMapResult = new HashMap<>();
        if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))) {
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
        }
        if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))) {
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));  //域对象
        }
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword"));
        AggregatedPage<SkuInfo> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class);
        if (searchMap == null || StringUtils.isEmpty(searchMap.get("category"))) {
            StringTerms categoryTerms = aggregatedPage.getAggregations().get("skuCategory");
            List<String> categoryList = getGroupList(categoryTerms);
            groupMapResult.put("categoryList", categoryList);
        }
        if (searchMap == null || StringUtils.isEmpty(searchMap.get("brand"))) {
            StringTerms brandTerms = aggregatedPage.getAggregations().get("skuBrand");
            List<String> brandList = getGroupList(brandTerms);
            groupMapResult.put("brandList", brandList);
        }
        StringTerms specTerms = aggregatedPage.getAggregations().get("skuSpec");
        //获取规格分组的集合数据--->实现合并 操作
        List<String> specList = getGroupList(specTerms);
        Map<String, Set<String>> specMap = putAllSpec(specList);
        groupMapResult.put("specList", specMap);
        return groupMapResult;

    }
获取分组集合数据
  /**
     * 获取分组集合数据
     *
     * @param stringTerms
     * @return
     */
    public List<String> getGroupList(StringTerms stringTerms) {
        List<String> groupList = new ArrayList<>();
        for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
            String filedName = bucket.getKeyAsString();
            groupList.add(filedName);
        }
        return groupList;
    }

4 最终代码

   @Override
    public Map SearchMap(Map<String, String> searchMap) {
        /**
         * 搜索条件封装
         */
        NativeSearchQueryBuilder nativeSearchQueryBuilder = buildBaseQuery(searchMap);
        HashMap<String, Object> map = searchList(nativeSearchQueryBuilder);
       
        Map<String, Object> groupMap = searchGroupList(nativeSearchQueryBuilder, searchMap);
        map.putAll(groupMap);
        return map;
    }

5:商品信息导入索引库

 @Override
    public void importData() {
        //调用Feign读取 Sku
        Result<List<Sku>> skuResult = skuFeign.findByStatus("1");
        //将List<Sku> 转成List<SkuInfo>
        List<SkuInfo> skuInfoList = JSON.parseArray(JSON.toJSONString(skuResult.getData()), SkuInfo.class);
        for (SkuInfo skuInfo : skuInfoList) {
            //skuInfo.getSpec()Map字符串 转成Map
            Map<String, Object> maps = JSON.parseObject(skuInfo.getSpec(), Map.class);
            //如果要生成动态的域,只需要将该域存入一个Map<String,Object>对象即可,
            // 该Map<String,Object>的key会自动生成一个域,域的名字为该Map的key
            //当前Map<String,Object>后面的Object的值会作为当前Sku对象该域的(key)对应的值
            skuInfo.setSpecMap(maps);
        }
        //调用Dao实现数据批量导入
        skuEsMapper.saveAll(skuInfoList);
    }

6 总结:

封装重复代码
目标
思路
代码
学会分析代码.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值