商品搜索

第7章 商品搜索
学习目标
根据搜索关键字查询
条件筛选
规格过滤
价格区间搜索
分页查询
排序查询
高亮查询
1 根据关键字查询

(1) changgou_service_search项目创建SearchService接口

public interface SearchService {
   /**
     * 全文检索
     * @param paramMap  查询参数
     * @return
     */
    public Map search(Map<String, String> paramMap) throws Exception;
}

(2) changgou_service_search项目创建SearchService接口实现类SearchServiceImpl

@Service
public class SearchServiceImpl implements SearchService {
   @Autowired
    private ElasticsearchTemplate esTemplate;
​
​
​
    //设置每页查询条数据
    public final static Integer PAGE_SIZE = 20;@Override
    public Map search(Map<String, String> searchMap) throws Exception {
   
        Map<String, Object> resultMap = new HashMap<>();//有条件才查询Es
        if (null != searchMap) {
   
            //组合条件对象
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            //0:关键词
            if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
   
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
               
            }


//4. 原生搜索实现类
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
nativeSearchQueryBuilder.withQuery(boolQuery);

        //10: 执行查询, 返回结果对象
      AggregatedPage<SkuInfo> aggregatedPage = esTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
   
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
   
​
                    List<T> list = new ArrayList<>();
​
                    SearchHits hits = searchResponse.getHits();
                    if (null != hits) {
   
                        for (SearchHit hit : hits) {
   
                            SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
​
                            list.add((T) skuInfo);
                        }
                    }
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });//11. 总条数
            resultMap.put("total", aggregatedPage.getTotalElements());
            //12. 总页数
            resultMap.put("totalPages", aggregatedPage.getTotalPages());
            //13. 查询结果集合
            resultMap.put("rows", aggregatedPage.getContent());return resultMap;
        }
        return null;
    }}
(3) changgou_service_search项目创建SearchController

@RestController
@RequestMapping("/sku_search")
public class SearchController {
   @Autowired
    private EsManagerService esManagerService;@Autowired
    private SearchService searchService;
    
     //对搜索入参带有特殊符号进行处理
    public void handlerSearchMap(Map<String,String> searchMap){
   if(null != searchMap){
   
            Set<Map.Entry<String, String>> entries = searchMap.entrySet();
            for (Map.Entry<String, String> entry : entries) {
   
                if(entry.getKey().startsWith("spec_")){
   
                    searchMap.put(entry.getKey(),entry.getValue().replace("+","%2B"));
                }
            }
        }}/**
     * 全文检索
     * @return
     */
    @GetMapping
    public Map search(@RequestParam Map<String, String> paramMap) throws Exception {
   
        //特殊符号处理
        handlerSearchMap(searchMap);
        Map resultMap = searchService.search(paramMap);
        return resultMap;
    }
}

(4) 测试

使用postmain访问 http://localhost:9009/sku_search?keywords=手机

2 条件筛选
在这里插入图片描述

用户有可能会根据分类搜索、品牌搜索,还有可能根据规格搜索,以及价格搜索和排序操作。根据分类和品牌搜索的时候,可以直接根据指定域搜索,而规格搜索的域数据是不确定的,价格是一个区间搜索,所以我们可以分为三段实现,先实现分类、品牌搜素,再实现规格搜索,然后实现价格区间搜索。

2.1 品牌筛选
2.1.1 需求分析
页面每次向后台传入对应的分类和品牌,后台据分类和品牌进行条件过滤即可。

2.1.2 代码实现
修改搜索微服务com.changgou.service.SearchServiceImpl的搜索方法,添加品牌过滤,代码如下:

代码如下:

@Override
public Map search(Map<String, String> searchMap) throws Exception {
   
    Map<String, Object> resultMap = new HashMap<>();//有条件才查询Es
    if (null != searchMap) {
   
        //组合条件对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //0:关键词
        if (StringUtils.isNotEmpty(searchMap.get("keywords"))) {
   
            boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
        }
        //1:条件 品牌
        if (StringUtils.isNotEmpty(searchMap.get("brand"))) {
   
            boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
        }
      //4. 原生搜索实现类
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQuery);//6. 品牌聚合(分组)查询
        String skuBrand = "skuBrand";
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));//10: 执行查询, 返回结果对象
        AggregatedPage<SkuInfo> aggregatedPage = esTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
   
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
   
​
                List<T> list = new ArrayList<>();
​
                SearchHits hits = searchResponse.getHits();
                if (null != hits) {
   
                    for (SearchHit hit : hits) {
   
                        SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
​
                        list.add((T) skuInfo);
                    }
                }
                return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
            }
        });//11. 总条数
        resultMap.put("total", aggregatedPage.getTotalElements());
        //12. 总页数
        resultMap.put("totalPages", aggregatedPage.getTotalPages());
        //13. 查询结果集合
        resultMap.put("rows", aggregatedPage.getContent());//14. 获取品牌聚合结果
        StringTerms brandTerms = (StringTerms) aggregatedPage.getAggregation(skuBrand);
        List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        resultMap.put("brandList", brandList);return resultMap;
    }
    return null;
}
 

2.1.3 测试
测试效果如下:

访问地址:http://localhost:9009/sku_search?keywords=手机

在这里插入图片描述

此时只能搜到华为手环设备

2.2 规格过滤
2.2.1 需求分析
在这里插入图片描述

规格这一部分,需要向后台发送规格名字以及规格值,我们可以按照一定要求来发送数据,例如规格名字以特殊前缀提交到后台:spec_网络制式:电信4G、spec_显示屏尺寸:4.0-4.9英寸

后台接到数据后,可以根据前缀spec_来区分是否是规格,如果以spec_xxx开始的数据则为规格数据,需要根据指定规格找信息。

在这里插入图片描述

上图是规格的索引存储格式,真实数据在spechMap.规格名字.keyword中,所以找数据也是按照如下格式去找:

spechMap.规格名字.keyword

2.2.2 代码实现
修改com.changgou.service.SearchServiceImpl的搜索方法,增加规格查询操作,代码如下:

代码如下:

@Override
public Map search(Map<String, String> searchMap) throws Exception {
   
    Map<String, Object> resultMap = new HashMap<>();//有条件才查询Es
    if (null != searchMap) {
   
        //组合条件对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //0:关键词
        if (!StringUtils.isEmpty(searchMap.get("keywords"))) {
   
            boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
        }
        //1:条件 品牌
        if (!StringUtils.isEmpty(searchMap.get("brand"))) {
   
            boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
        }//2:条件 规格
        for (String key : searchMap.keySet()) {
   
            if (key.startsWith("spec_")) {
   
                String value = searchMap.get(key).replace("%2B", "+");
                boolQuery.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword",value));
            }
        }//4. 原生搜索实现类
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQuery);
​
​
        //6. 品牌聚合(分组)查询
        String skuBrand = "skuBrand";
 nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));//7. 规格聚合(分组)查询
        String skuSpec = "skuSpec";
 nativeSearchQueryBuilder.addAggregation(AggregationBuilders.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值