品優購項目筆記(六):電商系統搜索解決方案

Solr

高亮、分頁、排序查詢

高亮搜索

solrTemplate.queryForHighlightPage(query, Item.class)

高亮的部分在這裏面,必須替換掉原來集合中的title部分
在這裏插入圖片描述
排序(默認會進行相關度排序):相關度排序,相關度越高,排的越前面

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private SolrTemplate solrTemplate;


    @Override
    public Map<String, Object> search(Map paramMap) {
        /**
         * 獲取查詢條件
         */
        //獲取查詢關鍵字
        String keywords = String.valueOf(paramMap.get("keywords"));
        //當前頁
        Integer pageNumber = Integer.parseInt(String.valueOf(paramMap.get("pageNo")));
        //每頁查詢條數
        Integer pageSize = Integer.parseInt(String.valueOf(paramMap.get("pageSize")));

        /**
         * 封裝查詢對象
         */
        //創建查詢對象
        HighlightQuery query = new SimpleHighlightQuery();
        //創建查詢條件對象
        Criteria criteria = new Criteria("item_keywords").is(keywords);
        //將查詢條件放入查詢對象
        query.addCriteria(criteria);
        //設置從第幾條開始查詢
        if (pageNumber == null || pageNumber <= 0){
            pageNumber = 1;
        }
        Integer start = (pageNumber-1)*pageSize;
        //設置從第幾條開始顯示
        query.setOffset(start);
        //設置每頁查詢多少條
        query.setRows(pageSize);
        //設置高亮選項
        HighlightOptions highlightOptions = new HighlightOptions();
        //設置哪個域需要高亮顯示
        highlightOptions.addField("item_title");
        //設置高亮前綴
        highlightOptions.setSimplePrefix("<em style='color:red'>");
        //設置高亮後綴
        highlightOptions.setSimplePostfix("</em>");
        //將高亮選項加入到查詢對象中
        query.setHighlightOptions(highlightOptions);

        /**
         * 查詢並返回結果
         */
        HighlightPage<Item> items = solrTemplate.queryForHighlightPage(query, Item.class);
        //獲取帶高亮的集合
        List<HighlightEntry<Item>> highlighted = items.getHighlighted();
        //存儲item集合
        List<Item> itemList = new ArrayList<>();
        //遍歷高亮集合
        for (HighlightEntry<Item> entry : highlighted) {
            //獲取不帶高亮的實體對象
            Item item = entry.getEntity();
            List<HighlightEntry.Highlight> highlights = entry.getHighlights();
            if (highlights != null && highlights.size()>0){
                //獲取到高亮標題集合
                List<String> highlightTitle = highlights.get(0).getSnipplets();
                if (highlightTitle != null && highlightTitle.size()>0){
                    //獲取到高亮標題
                    String title = highlightTitle.get(0);
                    item.setTitle(title);
                }
            }
            itemList.add(item);
        }

        Map<String,Object> resultMap = new HashMap<>();
        //查詢到的結果集
        resultMap.put("rows",itemList);
        //總頁數
        resultMap.put("totalPages",items.getTotalPages());
        //總條數
        resultMap.put("total",items.getTotalElements());
        return resultMap;
    }
}

過濾查詢(重點)

業務流程分析
在這裏插入圖片描述
搜索的整體業務流程分析:
第一步:高亮、分頁顯示商品
根據關鍵字進行商品的高亮、分頁查詢顯示(solr中查詢)。
第二步:顯示分類
根據關鍵字到solr中,進行分類的分組顯示(分組的目的是去重)
第三步:顯示品牌和規格

  1. 將分類、模板、品牌、規格等數據放入redis中(以上圖爲準)
  2. 根據上述查詢到的分類名稱,到redis中查詢模板id,根據模板id分別查詢品牌數據和規格數據,進行顯示

第四步:過濾顯示商品
接收前端傳遞過濾屬性,使用FilterQuery對象進行過濾

代碼(去除redis的存儲數據過程,默認已經存儲完成)

package cn.itcast.core.service;

import cn.itcast.core.pojo.item.Item;
import cn.itcast.core.util.Constants;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.*;

import java.util.*;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private SolrTemplate solrTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Map<String, Object> search(Map paramMap) {
        Map<String, Object> resultMap = highlightSearch(paramMap);
        //去solr中,分組查詢分類,並返回結果
        List<String> categoryList = searchGroupCategory(paramMap);
        resultMap.put("categoryList",categoryList);
        //從前端獲取分類
        String category = String.valueOf(paramMap.get("category"));
        if (category!=null & !"".equals(category)) {
            //如果點擊分類,則查詢第一個分類
            Map map = searchBrandListAndSpecList(category);
            resultMap.putAll(map);

        } else {
            //如果沒有點擊,則查詢點擊的分類
            Map map = searchBrandListAndSpecList(categoryList.get(0));
            resultMap.putAll(map);
        }

        return resultMap;
    }

    /**
     * 高亮、過濾、分頁查詢商品
     * @param paramMap
     * @return
     */
    private Map<String, Object> highlightSearch(Map paramMap){
        //獲取參數
        String keywords = String.valueOf(paramMap.get("keywords"));
        Integer pageNo = Integer.parseInt(String.valueOf(paramMap.get("pageNo")));
        Integer pageSize = Integer.parseInt(String.valueOf(paramMap.get("pageSize")));
        String category = String.valueOf(paramMap.get("category"));
        String brand = String.valueOf(paramMap.get("brand"));
        String spec = String.valueOf(paramMap.get("spec"));
        String price = String.valueOf(paramMap.get("price"));

        //設置查詢對象
        HighlightQuery query = new SimpleHighlightQuery();
        //設置查詢條件對象
        Criteria criteria = new Criteria("item_keywords").is(keywords);
        query.addCriteria(criteria);
        //設置高亮
        HighlightOptions highlightOptions = new HighlightOptions();
        highlightOptions.addField("item_title");
        highlightOptions.setSimplePrefix("<em style='color:red'>");
        highlightOptions.setSimplePostfix("</em>");
        query.setHighlightOptions(highlightOptions);
        //設置query屬性
        query.setRows(pageSize);
        Integer start = (pageNo-1)*pageSize;
        query.setOffset(start);

        //過濾查詢
        //分類過濾
        if (category!=null&&!"".equals(category)){
            FilterQuery filterQuery = new SimpleFilterQuery();
            Criteria filterCriteria = new Criteria("item_category").is(category);
            filterQuery.addCriteria(filterCriteria);
            query.addFilterQuery(filterQuery);
        }
        //品牌過濾
        if (brand!=null&&!"".equals(brand)){
            FilterQuery filterQuery = new SimpleFilterQuery();
            Criteria filterCriteria = new Criteria("item_brand").is(brand);
            filterQuery.addCriteria(filterCriteria);
            query.addFilterQuery(filterQuery);
        }
        //規格過濾
        if (spec!=null&&!"".equals(spec)){
            Map<String,String> map = JSON.parseObject(spec, Map.class);
            if (map!=null){
                Set<Map.Entry<String, String>> entries = map.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    FilterQuery filterQuery = new SimpleFilterQuery();
                    Criteria filterCriteria = new Criteria("item_spec_"+entry.getKey()).is(entry.getValue());
                    filterQuery.addCriteria(filterCriteria);
                    query.addFilterQuery(filterQuery);
                }
            }
        }
        //價格過濾
        if (price!=null && !"".equals(price)){
            String[] split = price.split("-");
            if (split!=null &&split.length==2){
                //如果最小值不等於0
                if (!"0".equals(split[0])){
                    FilterQuery filterQuery = new SimpleFilterQuery();
                    Criteria filterCriteria = new Criteria("item_price").greaterThanEqual(split[0]);
                    filterQuery.addCriteria(filterCriteria);
                    query.addFilterQuery(filterQuery);
                }
                //如果最大值不是*
                if (!"*".equals(split[1])){
                    FilterQuery filterQuery = new SimpleFilterQuery();
                    Criteria filterCriteria = new Criteria("item_price").lessThanEqual(split[1]);
                    filterQuery.addCriteria(filterCriteria);
                    query.addFilterQuery(filterQuery);
                }

            }
        }


        //獲取數據
        HighlightPage<Item> highlightPage = solrTemplate.queryForHighlightPage(query, Item.class);
        //替換高亮數據
        List<Item> itemList = new ArrayList<>();
        List<HighlightEntry<Item>> highlighted = highlightPage.getHighlighted();
        for (HighlightEntry<Item> entry : highlighted) {
            Item item = entry.getEntity();
            List<HighlightEntry.Highlight> highlights = entry.getHighlights();
            if (highlights!=null & highlights.size()>0){
                HighlightEntry.Highlight highlight = highlights.get(0);
                List<String> snipplets = highlight.getSnipplets();
                if (snipplets!=null && snipplets.size()>0){
                    String title = snipplets.get(0);
                    item.setTitle(title);
                }
            }
            itemList.add(item);
        }
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("total",highlightPage.getTotalElements());
        resultMap.put("totalPage",highlightPage.getTotalPages());
        resultMap.put("rows",itemList);

        return resultMap;
    }

    /**
     * 分組查詢分類數據
     * @param paramMap
     * @return
     */
    private List<String> searchGroupCategory(Map paramMap){
        //獲取參數
        String keywords = String.valueOf(paramMap.get("keywords"));

        //創建查詢對象
        Query query = new SimpleQuery();
        //創建查詢條件對象
        Criteria criteria = new Criteria("item_keywords").is(keywords);
        query.addCriteria(criteria);

        //設置分組查詢
        GroupOptions groupOptions = new GroupOptions();
        groupOptions.addGroupByField("item_category");
        query.setGroupOptions(groupOptions);

        //存儲category
        List<String> categoryList = new ArrayList<>();
        GroupPage<Item> items = solrTemplate.queryForGroupPage(query, Item.class);
        GroupResult<Item> item_category = items.getGroupResult("item_category");
        Page<GroupEntry<Item>> groupEntries = item_category.getGroupEntries();
        for (GroupEntry<Item> groupEntry : groupEntries) {
            String category = groupEntry.getGroupValue();
            categoryList.add(category);
        }
        return categoryList;
    }

    /**
     * 查詢品牌集合和規格集合
     * @return
     */
    private Map searchBrandListAndSpecList(String category){
        //獲取模板id
        Long id = (Long) redisTemplate.boundHashOps(Constants.CATEGORY_LIST_REDIS).get(category);
        //獲取品牌集合
        List<Map> brandList = (List<Map>) redisTemplate.boundHashOps(Constants.BRAND_LIST_REDIS).get(id);
        List<Map> specList = (List<Map>) redisTemplate.boundHashOps(Constants.SPEC_LIST_REDIS).get(id);
        Map resultMap = new HashMap();
        resultMap.put("brandList",brandList);
        resultMap.put("specList",specList);
        return resultMap;
    }
}

多關鍵字搜索

因爲默認會進行相關度排序,所有當多關鍵字搜索時,只需要將多關鍵字直接的空格去掉即可
在這裏插入圖片描述
所以,在獲取keywords時,將keywords中的空格,替換爲空字符串即可

//獲取關鍵字
String keywords = String.valueOf(paramMap.get("keywords"));
if (keywords!=null){
   	keywords = keywords.replaceAll(" ","");
}

價格排序

首先,獲取前端傳入的排序域和排序方式

String sortType = String.valueOf(paramMap.get("sort"));
String sortField = String.valueOf(paramMap.get("sortField"));

然後,進行排序,並將sort對象添加到query中即可

//添加排序
if (sortField!=null & sortType!=null & !"".equals(sortField) && !"".equals(sortType)){
     if ("ASC".equals(sortType)){
         Sort sort = new Sort(Sort.Direction.ASC,"item_"+sortField);
         query.addSort(sort);
     }
     if ("DESC".equals(sortType)){
         Sort sort = new Sort(Sort.Direction.DESC,"item_"+sortField);
         query.addSort(sort);
     }
 }

商品上架

在這裏插入圖片描述
商品上架業務流程:在管理員進行審覈通過時,將對應商品的所有庫存數據添加到solr中
在這裏插入圖片描述
GoodsController

/**
     * 修改審覈狀態
     * @param ids
     * @param status
     * @return
     */
    @RequestMapping("/updateStatus")
    public Result updateStatus(Long[] ids, String status){
        try {
            if (ids!=null){
                for (Long id : ids) {
                    //更新商品狀態
                    goodsService.updateStatus(id,status);
                    if ("1".equals(status)){
                        solrManagerService.importItemDataToSolr(id);
                    }
                }
            }
            return new Result(true,"狀態修改成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false,"狀態修改失敗!");
        }
    }

SolrManagerServiceImpl

@Service
public class SolrManagerServiceImpl implements SolrManagerService {
    @Autowired
    private SolrTemplate solrTemplate;
    @Autowired
    private ItemDao itemDao;

    public void importItemDataToSolr(Long id){
        ItemQuery itemQuery = new ItemQuery();
        ItemQuery.Criteria criteria = itemQuery.createCriteria();
        criteria.andGoodsIdEqualTo(id);
        List<Item> itemList = itemDao.selectByExample(itemQuery);
        if (itemList!=null){
            for (Item item : itemList) {
                //獲取json格式字符串
                String specJsonStr = item.getSpec();
                Map map = JSON.parseObject(specJsonStr, Map.class);
                item.setSpecMap(map);
            }
            //保存
            solrTemplate.saveBeans(itemList);
            //提交
            solrTemplate.commit();
        }

    }
}

商品下架

業務流程:當管理員或商家刪除商品時,同時從solr中,刪除對應商品的庫存數據

省略Controler中的代碼

/**
     * 根據商品id,去solr中刪除庫存數據
     * @param id
     */
    public void delete(Long id){
        Query query = new SimpleQuery();
        Criteria criteria = new Criteria("item_goodsid").is(id);
        query.addCriteria(criteria);
        solrTemplate.delete(query);
        solrTemplate.commit();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章