商品搜索完全實現代碼

 @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,所以傳值前要用非特殊符號替代下,接到參時再轉回來使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章