es自定义排序

## 排序

### 一、默认排序规则

默认情况下,是按照_score降序排序。
_score使用的算法,计算出一个索引中的文本,与搜索文本,他们之间的关联匹配程度
es使用的是,term frequency和inverse documnet frequency算法,简称为TF/IDF算法
term frequency:搜索文本中的各个词条在field文本中出现了多少次,出现次数越多,分数越高
inverse documnet frequency:搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,分数越低

从Elasticsearch 5之后, 缺省的打分机制改成了 __Okapi BM25__ 。
BM25 的 BM 是缩写自 Best Match, 25 貌似是经过 25 次迭代调整之后得出的算法,它也是基于 TF/IDF 进化来的。

Elasticsearch有三种控制相关度分数的方法:
- boost
- boosting
- function_score
评分公式
```
score(q,d)  =  queryNorm(q) //归一化因子
          · coord(q,d)              //协调因子
          · ∑ (           
                tf(t in d)          //词频
              · idf(t)²             //逆向文档频率
              · t.getBoost()        //权重
              · norm(t,d)           //字段长度归一值
            ) (t in q) 
```
搜索时指定某一个字段,权重加大,当 boost > 1 时, 打分的权重相对性提升

```
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("documentTitle", "201文")).boost(2.0f);
```
boosting
```
QueryBuilders.boostingQuery(QueryBuilders.matchQuery("documentTitle", "201文"),
QueryBuilders.matchQuery("flag", "123")).negativeBoost(0.2f);
```

function_score
```
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery().add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("documentTitle", searchContent)),ScoreFunctionBuilders.weightFactorFunction(1000)).add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("description", searchContent)),
ScoreFunctionBuilders.weightFactorFunction(100));

```


### 二、自定义排序

要实现自定义打分排序,需要使用funcion_score语法,它将query包装在内部,从而实现先召回 -> 再文本相关性评分 -> 最后自定义打分的功能。

官方文档链接
https://www.elastic.co/guide/en/elasticsearch/reference/7.9/query-dsl-function-score-query.html#function-field-value-factor
ES在5.x+版本后发明了一种语法类似javascript/groovy的专用脚本语言painless,我们需要写一个painless脚本,脚本中可以获取文本相关性得分,也可以获取文档的各个字段内容,也可以获取查询请求中传入的临时参数,综合来计算一个新的分数替代默认的文本相关性得分。

ES的自定义排序的推荐两种实现形式:基于脚本的自定义排序和基于native script的自定义排序。
||~版本||使用脚本||
||< Elasticsearch 1.4 ||MVEL 脚本||
||< Elasticsearch 5.0||Groovy 脚本||
||‘>= Elasticsearch 5.0||painless 脚本||

 __1. 基于Painless脚本的自定义排序__ 

先根据排序逻辑定义painless脚本,再用ScriptSortBuilder排序 

```
// 自定义评分规则
Map groupMap = new HashMap<>();
groupMap.put("华为", 4);
groupMap.put("三星", 3);
groupMap.put("苹果", 2);
groupMap.put("小米", 1);
Map params = new HashMap<>();
params.put("groupMap", groupMap);
Script script = new Script(ScriptType.INLINE, SortSetting.SORT_LANG_PAINLESS, SortSetting.SCRIPT_TEXT, params);//脚本文件名称,脚本类型
ScriptSortBuilder sortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);

```

Painless脚本
```
 `def groupScore = params.groupMap[doc['title'].value];groupScore != null?groupScore:0;` 

```


 

你可能感兴趣的:(自定义排序,es,elasticsearch,java)