1 需求分析
以关键字作为查询条件,查询结果中包含的商品分类,在页面中显示出来
2 实现思路
(1)商品分类列表的显示使用聚合查询
(2)使用过滤查询
3 代码实现
修改SearchServiceImpl的search方法,在第一段代码(封装查询请求)的末尾处添加以下代码:
package com.changgou.service;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :lijunxuan
* @date :Created in 2019/7/17 19:00
* @description :
* @version: 1.0
*/
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private RestHighLevelClient restHighLevelClient;
//设置每页查询条数据
public final static Integer PAGE_SIZE = 4;
@Override
public Map search(Map<String, String> paramMap) throws Exception {
Map<String,Object> resultMap=new HashMap<>();
/**
* 1.获取查询参数
*/
//查询关键字
String keywords = paramMap.get("keywords");
//当前页数
String pageNo = paramMap.get("pageNo");
//按照什么域进行排序
String sort = paramMap.get("sort");
//排序方式是升序还是降序
String sortOrder = paramMap.get("sortOrder");
/**
* 2.获取查询需要的对象
*/
//创建查询对象,指定索引库名称,_index
SearchRequest searchRequest = new SearchRequest("sku");
//指定查询索引库中的类型
searchRequest.types("doc");
//创建查询构造对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//创建布尔查询(组合查询对象)
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
/**
* 3.设置根据关键字查询(关键字需要中文分词)
*/
MatchQueryBuilder nameQueryBuilder = QueryBuilders.matchQuery("name", keywords);
//根据名称查询条件放入组合查询对象中
boolQueryBuilder.must(nameQueryBuilder);
/**
* 4. 设置高亮查询
*/
HighlightBuilder highlightBuilder = new HighlightBuilder();
//设置在哪个域中高亮显示
highlightBuilder.field("name");
//设置高亮前缀
highlightBuilder.preTags("<em style=\"color:red\">");
//设置高亮后缀
highlightBuilder.postTags("</em>");
searchSourceBuilder.highlighter(highlightBuilder);
/**
* 5. 设置分页查询
*/
if (StringUtils.isEmpty(pageNo)) {
paramMap.put("pageNo", "1");
resultMap.put("pageNo", "1");
}
Integer pageNoTemp = Integer.parseInt(pageNo);
if (pageNoTemp < 1) {
paramMap.put("pageNo", "1");
resultMap.put("pageNo", "1");
pageNoTemp = 1;
}
//从第几条开始查询
Integer start = (pageNoTemp - 1) * PAGE_SIZE;
//从第几条开始查询
searchSourceBuilder.from(start);
//每页查询多少条数据
searchSourceBuilder.size(PAGE_SIZE);
/**
* 6. 设置排序查询
*/
if (!StringUtils.isEmpty(sort)) {
//升序
if ("ASC".equals(sortOrder)) {
searchSourceBuilder.sort(sort, SortOrder.ASC);
}
//降序
if ("DESC".equals(sortOrder)) {
searchSourceBuilder.sort(sort, SortOrder.DESC);
}
}
/**
* 7. 设置根据分类聚合查询
* 其实就是按照分类名称分组查询, 目的是找到根据当前的关键字, 查询出对应的分类, 并且要去除掉重复的分类
* tems中传入的是聚合组的名称, 可以随意起名, 但是不要重复
*/
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("categoryGroup").field("categoryName");
searchSourceBuilder.aggregation(termsAggregationBuilder);
/**
* 12.查询并返回的结果
*/
//将组合查询条件放入查询构造对象中
searchSourceBuilder.query(boolQueryBuilder);
//将组合查询条件放入查询请求中
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
/**
* 13. 获取查询到的结果集, 封装后返回
*/
SearchHits searchHits = searchResponse.getHits();
//获取查询到的总条数
long totalHits = searchHits.getTotalHits();
resultMap.put("total",totalHits);
//获取查询结果集
SearchHit[] hits = searchHits.getHits();
List rows = new ArrayList<>();
if (hits!=null){
for (SearchHit hit : hits) {
//获取普通的查询出来的一条数据(不带高亮名称)
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields != null) {
HighlightField highlightField = highlightFields.get("name");
Text[] fragments = highlightField.fragments();
if (fragments != null && fragments.length > 0) {
//将高亮名称放入查询出来的数据中, 覆盖原来不带高亮的名称
sourceAsMap.put("name", fragments[0].toString());
}
}
rows.add(sourceAsMap);
}
}
resultMap.put("rows",rows);
/**
* 14. 获取根据分类聚合查询结果
*/
Aggregations aggregations = searchResponse.getAggregations();
//将聚合结果转换成Map
Map<String, Aggregation> asMap = aggregations.getAsMap();
//根据分组名称获取聚合的具体结果
Terms terms = (Terms)asMap.get("categoryGroup");
//获取分组后集合中的具体内容
List<? extends Terms.Bucket> buckets = terms.getBuckets();
List<String> categoryList = new ArrayList<>();
if (buckets != null) {
for (Terms.Bucket bucket : buckets) {
categoryList.add(bucket.getKeyAsString());
}
}
resultMap.put("categoryList", categoryList);
return resultMap;
}
}