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中,进行分类的分组显示(分组的目的是去重)
第三步:显示品牌和规格
- 将分类、模板、品牌、规格等数据放入redis中(以上图为准)
- 根据上述查询到的分类名称,到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();
}