美文网首页
商品搜索完全实现代码

商品搜索完全实现代码

作者: 月哥说了算 | 来源:发表于2019-08-22 21:33 被阅读0次
     @Override
        public Map searchSkuInfoByEs(Map<String, String> searchmap) {
            Map map=new HashMap<>();
            //条件对象  目标:为了合并 搜索条件及排序及分页及高亮
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            //组合条件对象
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    
            //本次查询关键词
            if(null!=searchmap.get("keywords") && !"".equals(searchmap.get("keywords").trim())){
                boolQueryBuilder.must(QueryBuilders.matchQuery("name",searchmap.get("keywords")).operator(Operator.AND));
            }
            else {
           //默认搜索条件
            }
            //本次查询品牌
            if(null!=searchmap.get("brand")&&!"".equals(searchmap.get("brand").trim())){
               boolQueryBuilder.filter(QueryBuilders.termQuery("brandName",searchmap.get("brand")));
            }
            //本次规格查询
            Set<Map.Entry<String, String>> entries = searchmap.entrySet();
            if(null!=entries&&entries.size()>0){
                for (Map.Entry<String, String> entry : entries) {
                    if(entry.getKey().startsWith("spec_")){
                        //feign传值会去掉特殊符号,这里 转下
                        String replace = entry.getValue().replace("%2B", "+");
                        boolQueryBuilder.filter(QueryBuilders.termQuery("specMap."+entry.getKey().substring(5)+".keyword",replace));
                    }
                }
            }
    
            //本次价格查询
            //价格区间  500-1000  3000
            if (null != searchmap.get("price") && !"".equals(searchmap.get("price").trim())) {
                String[] prices = searchmap.get("price").split("-");
                if(prices.length==2){
                    //>=    <
                    boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0]).lt(prices[1]));
                }
                else if(prices.length==1){
                    //>=
                    boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
                }
            }
    
    
            //高亮
            HighlightBuilder.Field highName = new HighlightBuilder.Field("name");
            highName.preTags("<span style='color:red'>");
            highName.postTags("</span>");
            nativeSearchQueryBuilder.withHighlightFields(highName);
    
            //排序
            //sortRule=ASC&sortField=price
            if (null != searchmap.get("sortRule") && !"".equals(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));
                }
            }
    
           //分页
            String pageNum=searchmap.get("pageNum");
            if(StringUtils.isEmpty(pageNum)){
                 pageNum="1";
            }
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.valueOf(pageNum)-1,Page.pageSize));
            nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
    
    
           //品牌集合查询
            //设置别名
            String skuBrandName="skuBrandName";
            TermsAggregationBuilder brandName = AggregationBuilders.terms(skuBrandName).field("brandName");
            //放到原生对象
            nativeSearchQueryBuilder.addAggregation(brandName);
    
    
            //规格集合查询查询
            String specName="specName";
            TermsAggregationBuilder specNameBuilder = AggregationBuilders.terms(specName).field("spec.keyword");
            nativeSearchQueryBuilder.addAggregation(specNameBuilder);
    
            AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    List<T> content = new ArrayList<>();
    
                    //总条数
    //                "hits": {
    //                    "total": 90830,
    //                            "max_score": 1,
    //                            "hits": [
    //                    {
    //                        "_index": ".kibana",
    //                            "_type": "config",
    //                            "_id": "5.6.8",
    //                            "_score": 1,
    //                            "_source": {
    //                        "buildNum": 15616,
    //                                "defaultIndex": "AWvrbNEDfJIoQxXR4Osp"
    //                    }
    //                    },
                    SearchHits hits = searchResponse.getHits();
                    //"hits": [
                    ////                    {
                    ////                        "_index": ".kibana",
                    ////                            "_type": "config",
                    ////                            "_id": "5.6.8",
                    ////                            "_score": 1,
                    ////                            "_source": {
                    ////                        "buildNum": 15616,
                    ////                                "defaultIndex": "AWvrbNEDfJIoQxXR4Osp"
                    ////                    }
                    ///.....搜索到的所有信息都在这个数组里 ,下面得到他
                    SearchHit[] hits1 = hits.getHits();
                    //遍历每条信息
                    for (SearchHit documentFields : hits1) {
    
                     /*           { "id": 27598311688,
                                        "name": "小米(MI) 小米6X 手机 全网通 手机 曜石黑 6GB 128GB",
                                        "price": 61900,
                                        "num": 10000,
                                        "image": "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/15859/22/1559/207576/5c136ab1E271f0be2/8d8e5e8dce11aea2.jpg!q70.jpg.webp",
                                        "status": "1",
                                        "createTime": 1556668800000,
                                        "updateTime": 1556668800000,
                                        "isDefault": null,
                                        "spuId": 2759831168300,
                                        "categoryId": 0,
                                        "categoryName": "手机",
                                        "brandName": "小米",
                                        "spec": """{"颜色": "红色", "版本": "6GB+128GB"}""",
                                        "specMap": {
                                    "颜色": "红色",
                                            "版本": "6GB+128GB"
                                }*/
                         //得到搜索信息的json串
                        String sourceAsString = documentFields.getSourceAsString();
                        //转为对象
                        SkuInfo skuInfo = JSON.parseObject(sourceAsString, SkuInfo.class);
    
                        //判断是否有高亮的值
                        //k:name v:GOGER远近两用老花镜男多焦点看高清双光<span style='color:red'>眼</span>架 看远看近300度(建议65~69岁)
                        //可能有多个字段需要高亮所以用map放
                        Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
                        if(null != highlightFields && highlightFields.size() > 0){
                            //得到name字段获取高亮信息
                            HighlightField highlightField = highlightFields.get("name");
                            //GOGER远近两用老花镜男多焦点看高清双光<span style='color:red'>眼</span>架 看远看近300度(建议65~69岁)
                            Text[] fragments = highlightField.getFragments();
                            if(null != fragments && fragments.length > 0){
                                //把高亮完的放到skuInfo
                                String hname = fragments[0].toString();
                                skuInfo.setName(hname);
                            }
                        }
    
    
                        content.add((T)skuInfo);
    
                    }
    
                    long totalHits = hits.totalHits;
                    Aggregations aggregations = searchResponse.getAggregations();
                    //结果集
                    //分页
                    //分组
                    //需要用到的对象丢到里面
                    return new AggregatedPageImpl<T>(content,pageable,totalHits,aggregations);
                }
            });
    
            //拿品牌集合
            Terms aggregations =(Terms) page.getAggregation(skuBrandName);
            //得到品牌集合
            List<String> brandNamecollect = aggregations.getBuckets().stream().map(c -> ((Terms.Bucket) c).getKeyAsString()).collect(toList());
             //得到规格集合
            Terms specNameAgg =(Terms)page.getAggregation(specName);
            List<String> specNamecollect = specNameAgg.getBuckets().stream().map(c -> ((Terms.Bucket) c).getKeyAsString()).collect(toList());
            Map<String,Set<String>> specMap=buildModel(specNamecollect);
    
            List<SkuInfo> content = page.getContent();
            map.put("rows",content);
            map.put("pageNum",pageNum);
            map.put("total",page.getTotalElements());
            map.put("brandList",brandNamecollect);
            map.put("specList",specMap);
            return map;
        }
    
        private Map<String,Set<String>> buildModel(List<String> specNamecollect) {
            Map<String,Set<String>> map=null;
            if(null!=specNamecollect&&specNamecollect.size()>0){
                map=new HashMap<>();
                for (String spec : specNamecollect) {
                    Map<String,String> jsonMap = JSON.parseObject(spec, Map.class);
                    Set<Map.Entry<String, String>> entries = jsonMap.entrySet();
                    for (Map.Entry<String, String> entry : entries) {
                        Set<String> set=map.get(entry.getKey());
                        if(null==set){
                            set=new HashSet<>();
                        }
                        set.add(entry.getValue());
                        map.put(entry.getKey(),set);
                    }
                }
            }
            return map;
        }
    

    controller:

    //因为feign方式传参时特殊符号会去掉所以需要用别的东西替换。
     public Map<String,String> handerModel(Map<String,String> searchmap){
            if(null!=searchmap&&searchmap.size()>0){
                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 searchmap;
        }
    @GetMapping
        public String searchGoods(Model model,@RequestParam Map<String,String> searchmap){
            searchmap=handerModel(searchmap);
            Map map = webSearchService.searchSkuInfoByEs(searchmap);
            model.addAttribute("result",map);
            model.addAttribute("searchMap",searchmap);
            model.addAttribute("page",new Page((int)map.get("total"),Integer.valueOf(map.get("pageNum").toString()),Page.pageSize));
            //http://search.changgou.com:9011/wsearch?keywords=手机
            StringBuilder url = new StringBuilder();
            url.append("http://search.changgou.com:9011/wsearch");
            if(null!=searchmap&&searchmap.size()>0){
                url.append("?");
                Set<Map.Entry<String, String>> entries = searchmap.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    //防止键值对有重复,去掉
                    if("pageNum".equals(entry.getKey())||"sortRule".equals(entry.getKey())
                            || "sortField".equals(entry.getKey())){
    
                    }
                    else {
                        url.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                    }
                }
            }
            model.addAttribute("url",url.toString());
            return "search";
        }
    

    这里需要注意的是Feign方式传参会 去掉特殊符号,比如这里当传4G+64G时,会变为4G 64G,所以传值前要用非特殊符号替代下,接到参时再转回来使用。

    相关文章

      网友评论

          本文标题:商品搜索完全实现代码

          本文链接:https://www.haomeiwen.com/subject/pxzosctx.html