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;
}
 

 

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