1. 程式人生 > 其它 >ElasticSearch中單個商品按不同區域定價及排序(多欄位組合排序) ScriptSortBuilder

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();
//String scriptStr = " return doc['price'].value + (doc['regionPriceVarianceMap." + buyerDistrictId + "'].size()==0?0:doc['regionPriceVarianceMap." + buyerDistrictId + "'].value)";
String scriptStr = " return doc['price'].value + " +
"(doc.containsKey('regionPriceVarianceMap." + buyerDistrictId + "')" +
"?(doc['regionPriceVarianceMap." + buyerDistrictId + "'].size()==0?0" +
":doc['regionPriceVarianceMap." + buyerDistrictId + "'].value):0)";
Script script = new Script(scriptStr);
ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER);
return scriptSortBuilder;
}