@Override
public Map searchSkuInfoByEs(Map<String, String> searchmap) {
Map map=new HashMap<>();
//条件对象 目标:为了合并 搜索条件及排序及分页及高亮
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//组合条件对象
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//本次查询关键词
if(null!=searchmap.get("keywords") && !"".equals(searchmap.get("keywords").trim())){
boolQueryBuilder.must(QueryBuilders.matchQuery("name",searchmap.get("keywords")).operator(Operator.AND));
}
else {
//默认搜索条件
}
//本次查询品牌
if(null!=searchmap.get("brand")&&!"".equals(searchmap.get("brand").trim())){
boolQueryBuilder.filter(QueryBuilders.termQuery("brandName",searchmap.get("brand")));
}
//本次规格查询
Set<Map.Entry<String, String>> entries = searchmap.entrySet();
if(null!=entries&&entries.size()>0){
for (Map.Entry<String, String> entry : entries) {
if(entry.getKey().startsWith("spec_")){
//feign传值会去掉特殊符号,这里 转下
String replace = entry.getValue().replace("%2B", "+");
boolQueryBuilder.filter(QueryBuilders.termQuery("specMap."+entry.getKey().substring(5)+".keyword",replace));
}
}
}
//本次价格查询
//价格区间 500-1000 3000
if (null != searchmap.get("price") && !"".equals(searchmap.get("price").trim())) {
String[] prices = searchmap.get("price").split("-");
if(prices.length==2){
//>= <
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0]).lt(prices[1]));
}
else if(prices.length==1){
//>=
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
}
}
//高亮
HighlightBuilder.Field highName = new HighlightBuilder.Field("name");
highName.preTags("<span style='color:red'>");
highName.postTags("</span>");
nativeSearchQueryBuilder.withHighlightFields(highName);
//排序
//sortRule=ASC&sortField=price
if (null != searchmap.get("sortRule") && !"".equals(searchmap.get("sortRule"))) {
if("ASC".equals(searchmap.get("sortRule"))){
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchmap.get("sortField")).order(SortOrder.ASC));
}
else {
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchmap.get("sortField")).order(SortOrder.DESC));
}
}
//分页
String pageNum=searchmap.get("pageNum");
if(StringUtils.isEmpty(pageNum)){
pageNum="1";
}
nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.valueOf(pageNum)-1,Page.pageSize));
nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
//品牌集合查询
//设置别名
String skuBrandName="skuBrandName";
TermsAggregationBuilder brandName = AggregationBuilders.terms(skuBrandName).field("brandName");
//放到原生对象
nativeSearchQueryBuilder.addAggregation(brandName);
//规格集合查询查询
String specName="specName";
TermsAggregationBuilder specNameBuilder = AggregationBuilders.terms(specName).field("spec.keyword");
nativeSearchQueryBuilder.addAggregation(specNameBuilder);
AggregatedPage<SkuInfo> page = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
List<T> content = new ArrayList<>();
//总条数
// "hits": {
// "total": 90830,
// "max_score": 1,
// "hits": [
// {
// "_index": ".kibana",
// "_type": "config",
// "_id": "5.6.8",
// "_score": 1,
// "_source": {
// "buildNum": 15616,
// "defaultIndex": "AWvrbNEDfJIoQxXR4Osp"
// }
// },
SearchHits hits = searchResponse.getHits();
//"hits": [
//// {
//// "_index": ".kibana",
//// "_type": "config",
//// "_id": "5.6.8",
//// "_score": 1,
//// "_source": {
//// "buildNum": 15616,
//// "defaultIndex": "AWvrbNEDfJIoQxXR4Osp"
//// }
///.....搜索到的所有信息都在这个数组里 ,下面得到他
SearchHit[] hits1 = hits.getHits();
//遍历每条信息
for (SearchHit documentFields : hits1) {
/* { "id": 27598311688,
"name": "小米(MI) 小米6X 手机 全网通 手机 曜石黑 6GB 128GB",
"price": 61900,
"num": 10000,
"image": "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/15859/22/1559/207576/5c136ab1E271f0be2/8d8e5e8dce11aea2.jpg!q70.jpg.webp",
"status": "1",
"createTime": 1556668800000,
"updateTime": 1556668800000,
"isDefault": null,
"spuId": 2759831168300,
"categoryId": 0,
"categoryName": "手机",
"brandName": "小米",
"spec": """{"颜色": "红色", "版本": "6GB+128GB"}""",
"specMap": {
"颜色": "红色",
"版本": "6GB+128GB"
}*/
//得到搜索信息的json串
String sourceAsString = documentFields.getSourceAsString();
//转为对象
SkuInfo skuInfo = JSON.parseObject(sourceAsString, SkuInfo.class);
//判断是否有高亮的值
//k:name v:GOGER远近两用老花镜男多焦点看高清双光<span style='color:red'>眼</span>架 看远看近300度(建议65~69岁)
//可能有多个字段需要高亮所以用map放
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
if(null != highlightFields && highlightFields.size() > 0){
//得到name字段获取高亮信息
HighlightField highlightField = highlightFields.get("name");
//GOGER远近两用老花镜男多焦点看高清双光<span style='color:red'>眼</span>架 看远看近300度(建议65~69岁)
Text[] fragments = highlightField.getFragments();
if(null != fragments && fragments.length > 0){
//把高亮完的放到skuInfo
String hname = fragments[0].toString();
skuInfo.setName(hname);
}
}
content.add((T)skuInfo);
}
long totalHits = hits.totalHits;
Aggregations aggregations = searchResponse.getAggregations();
//结果集
//分页
//分组
//需要用到的对象丢到里面
return new AggregatedPageImpl<T>(content,pageable,totalHits,aggregations);
}
});
//拿品牌集合
Terms aggregations =(Terms) page.getAggregation(skuBrandName);
//得到品牌集合
List<String> brandNamecollect = aggregations.getBuckets().stream().map(c -> ((Terms.Bucket) c).getKeyAsString()).collect(toList());
//得到规格集合
Terms specNameAgg =(Terms)page.getAggregation(specName);
List<String> specNamecollect = specNameAgg.getBuckets().stream().map(c -> ((Terms.Bucket) c).getKeyAsString()).collect(toList());
Map<String,Set<String>> specMap=buildModel(specNamecollect);
List<SkuInfo> content = page.getContent();
map.put("rows",content);
map.put("pageNum",pageNum);
map.put("total",page.getTotalElements());
map.put("brandList",brandNamecollect);
map.put("specList",specMap);
return map;
}
private Map<String,Set<String>> buildModel(List<String> specNamecollect) {
Map<String,Set<String>> map=null;
if(null!=specNamecollect&&specNamecollect.size()>0){
map=new HashMap<>();
for (String spec : specNamecollect) {
Map<String,String> jsonMap = JSON.parseObject(spec, Map.class);
Set<Map.Entry<String, String>> entries = jsonMap.entrySet();
for (Map.Entry<String, String> entry : entries) {
Set<String> set=map.get(entry.getKey());
if(null==set){
set=new HashSet<>();
}
set.add(entry.getValue());
map.put(entry.getKey(),set);
}
}
}
return map;
}
controller:
//因为feign方式传参时特殊符号会去掉所以需要用别的东西替换。
public Map<String,String> handerModel(Map<String,String> searchmap){
if(null!=searchmap&&searchmap.size()>0){
Set<Map.Entry<String, String>> entries = searchmap.entrySet();
for (Map.Entry<String, String> entry : entries) {
if(entry.getKey().startsWith("spec_")){
searchmap.put(entry.getKey(),entry.getValue().replace("+","%2B"));
}
}
}
return searchmap;
}
@GetMapping
public String searchGoods(Model model,@RequestParam Map<String,String> searchmap){
searchmap=handerModel(searchmap);
Map map = webSearchService.searchSkuInfoByEs(searchmap);
model.addAttribute("result",map);
model.addAttribute("searchMap",searchmap);
model.addAttribute("page",new Page((int)map.get("total"),Integer.valueOf(map.get("pageNum").toString()),Page.pageSize));
//http://search.changgou.com:9011/wsearch?keywords=手机
StringBuilder url = new StringBuilder();
url.append("http://search.changgou.com:9011/wsearch");
if(null!=searchmap&&searchmap.size()>0){
url.append("?");
Set<Map.Entry<String, String>> entries = searchmap.entrySet();
for (Map.Entry<String, String> entry : entries) {
//防止键值对有重复,去掉
if("pageNum".equals(entry.getKey())||"sortRule".equals(entry.getKey())
|| "sortField".equals(entry.getKey())){
}
else {
url.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
}
}
model.addAttribute("url",url.toString());
return "search";
}
这里需要注意的是Feign方式传参会 去掉特殊符号,比如这里当传4G+64G时,会变为4G 64G,所以传值前要用非特殊符号替代下,接到参时再转回来使用。