1.定位问题:
a.字面意思是,ElasticSearch5分钟内执行脚本编译超过75个,编译太多而拒绝编译。编译是非常耗时的,这是ES的自我保护功能。
b.我的操作是动态评分通过script实现去了。
{
"query": {
"function_score": {
"functions": [
{
"script_score": {
"script": {
"source": "_score * ((doc['scoreWords'].values.contains('大米')) ? 2.0 : 1.0)",
"lang": "painless"
}
}
}
]
}
}
}
2.寻求解决办法:一般而言是由两种解决办法,一是调高限制。二是采用filter+权重评分。
a.调高限制,官方操作方法:
PUT _cluster/settings
{
"transient" : {
"script.max_compilations_rate" : "100/1m"
}
}
b.寻找替代方法:
BoolQueryBuilder bool = QueryBuilders.boolQuery();
for (String s : lexemeSet) {
bool.must(QueryBuilders.termQuery("searchWordsScore", s));
}
FunctionScoreQueryBuilder.FilterFunctionBuilder mainTitle = new FunctionScoreQueryBuilder
.FilterFunctionBuilder(bool, ScoreFunctionBuilders.weightFactorFunction(2.0f));
3.事后查看源码,研究原理:
a.报错位置在ScriptService类里面做的限制
// If there is enough tokens in the bucket, allow the request and decrease the tokens by 1
if (scriptsPerMinCounter >= 1) {
scriptsPerMinCounter -= 1.0;
} else {
// Otherwise reject the request
throw new CircuitBreakingException("[script] Too many dynamic script compilations within one minute, max: [" +
totalCompilesPerMinute + "/min]; please use on-disk, indexed, or scripts with parameters instead; " +
"this limit can be changed by the [" + SCRIPT_MAX_COMPILATIONS_PER_MINUTE.getKey() + "] setting");
}
b.从这段代码知道,编译其实是会缓存的,如果语句内容不变是不会重新编译的,继续看看这个key跟什么有关。
c.key和lang,code还有options,本实例是跟code有关。code的"大米是我动态传的,所以瞬间就超过了限制"。
CacheKey cacheKey = new CacheKey(lang, idOrCode, options);
解决办法
将参数写入params,源码source就不需要重复编译。
GET /_search
{
"query": {
"function_score": {
"query": {
"match": { "message": "elasticsearch" }
},
"script_score" : {
"script" : {
"params": {
"a": 5,
"b": 1.2
},
"source": "params.a / Math.pow(params.b, doc['likes'].value)"
}
}
}
}
}