@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,所以傳值前要用非特殊符號替代下,接到參時再轉回來使用。