ElasticSearch中單個商品按不同區域定價及排序(多字段組合排序) ScriptSortBuilder

產品需求:商品有一個通用價格字段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;
}
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章