品优购项目笔记(六):电商系统搜索解决方案

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();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章