转自:http://www.dcharm.com/?p=469
本文讨论ES的自定义排序的两种实现形式:基于groovy脚本的自定义排序和基于native script的自定义排序。
1. 基于Groovy脚本的自定义排序
ES的排序脚本必须放在config/scripts下面,ES能够自动发现这些脚本并提供对外使用, 例如编写脚本calculate-score.groovy
log(_score*2)+my_modifier
脚本中my_modifier是搜索请求中的参数,_score是ES计算得到的文档分数。发起搜索请求时指定用calculate-score排序
curl -XPOST localhost:9200/_search -d '{
"query": {
"function_score": {
"query": {
"match": {
"body": "foo"
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"script_file": "calculate-score",
"params": {
"my_modifier": 8
}
}
}
]
}
}}'
在上面的请求指定了my_modifier的值为8,排序时calculate-score脚本中对应变量my_modifier就会被赋值为8。除此以外,还可以在脚本中通过doc[‘field_name’].value或者doc[‘field_name’].value获取field data中的字段;通过_fields[‘field_name’]获取没有存放在doc values中但是放在了ES存储(store)中的字段。需要注意的是doc values会被载入到内存,而store不会,所以doc values取值速度更快。
ES会周期性的扫描config/scripts下面的文件,新增和被修改的脚本会被重新载入,并从script缓存中删除文件夹中被删除的脚本。重载的频率可以在watcher.interval中说明,默认是60s。如果要禁止重载脚本,可以设置script.auto_reload_enabled为false。
2. 基于native脚本的自定义排序
ES中的native脚本使用java语言编写,并需要实现相应的NativeScriptFactory接口。
public class CustomScriptFactory implements NativeScriptFactory {
@Override
publicExecutableScript newScript(@NullableMap params) {
returnnewCustomScript(params);
}
}
public class CustomScript extends AbstractDoubleSearchScript {
private double myVal;
private double base;
public CustomScript(@NullableMap params){
base = (Double)params.get("myVal");
}
@Override
public double runAsDouble() {
doublea = ((ScriptDocValues.Longs)doc().get("itemNum")).getValue();
returna +2;
}
}
将打包后的jar包放到ES的class path中,并在配置文件config/elasticsearch.yml中增加一行配置:
script.native.mynativescript.type: com.ymatou.search.searcher.script.CustomScriptFactory
Native脚本不能被ES自动发现,需要重启ES,另外搜索请求的格式也有些不同。
curl -XPOST localhost:19200/m2c/item/_search -d '{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"script_score": {
"lang":"native",
"script":"m2c_jyh_base",
"params": {
"myVal": 10.0
}
}
}
]
}
}
}'
3. Groovy脚本自定义排序和Native自定排序的比较
相对于Native自定义排序,Groovy脚本自定义排序实现和部署方便:不用编译打包,不用修改配置文件,也不用重启ES,但是Native自定义排序的速度是Groovy脚本自定义排序速度的1到3倍,因此建议大家使用Groovy脚本做实验,但是在生产环境中使用Native脚本。