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();
}