產品需求:商品有一個通用價格字段price,該商品可以設置不同區域的價格有不同的價格,如果有些區域沒有設置價格,那就是顯示通用價格。
一對多,在ElasticSearch索引文件中以map的形式存儲區域價格數據,key是區域ID,value是區域價格。沒有區域價格的用戶要顯示通用價格 也就是price字段,所以排序的時候利用price 與區域價格相加的 然後排序的方式,區域價格在存儲到es時與通用價格進行了差值處理,所以在區域價格的map中存儲的是兩者的差。這樣有區域價格的用戶 與沒有區域價格的用戶 利用兩個字段相加的和就能得到當前用戶實際要展示的價格。
可以在匹配到搜索結果後再處理價格從map中取出對應區域的價格返回給前端。但是拉下來有一個問題就是價格排序,按價格升序或者降序後,由於重新賦值了區域價格,這樣給前端的數據價格就是亂的。
在搜索參數中已經有用戶的區域ID,那麼能不能 在es中就按區域價格排序呢,搜了一翻資料後,發現可以在ElasticSearch排序條件中用script來實現。
es中數據如下
1.kibana http請求
get price_demo/_search
{"query":{"match": {
"name": "測試"
}},
"sort":[{
"_script" : {
"script" : {
"source" : " return doc['price'].value + (doc.containsKey('regionPriceVarianceMap.900097.keyword')?(doc['regionPriceVarianceMap.900097.keyword'].size()==0?0:doc['regionPriceVarianceMap.900097.keyword'].value):0)",
"lang" : "painless"
},
"type" : "number",
"order" : "asc"
}
}
]
}
2java代碼,代碼中判斷了當前區域字段是否存在,不存在則默認爲0
private void setSort(NativeSearchQueryBuilder searchQueryBuilder, SearchParameter param) {
if (param.getSortType() == null || param.getSortType().equals(0)) {
//綜合排序(設置的sort字段降序,價格升序)
searchQueryBuilder.withSort(SortBuilders.fieldSort(EsProductFields.SORT).order(SortOrder.DESC));
searchQueryBuilder.withSort(getScriptSortBuilder(param).order(SortOrder.ASC));
}
}
public ScriptSortBuilder getScriptSortBuilder(SearchParameter param) {
Long buyerDistrictId = param.getBuyerDistrictId() == null ? 0L : param.getBuyerDistrictId();
StringBuilder sb=new StringBuilder();
sb.append(" double price=doc['price'].value; ");
sb.append(" double districtPrice=0; ");
sb.append(" if(doc.containsKey('regionPriceVarianceMap."+ buyerDistrictId + "'))");
sb.append(" && doc['regionPriceVarianceMap." + buyerDistrictId + "'].size()!=0 { ");
sb.append(" districtPrice=doc['regionPriceVarianceMap." + buyerDistrictId + "'].value;");
sb.append(" } ");
sb.append(" return price+districtPrice; ");
Script script = new Script(sb.toString());
ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER);
return scriptSortBuilder;
}