Elasticsearch Painless脚本查询触发动态脚本编译超限报错求助
问题根因
Elasticsearch默认限制动态Painless脚本的编译频率为最多75次/5分钟,你遇到的报错正是触达了该阈值:
- 每个首次执行的动态脚本都会被ES编译,编译后的脚本会放入缓存复用,但若每次请求传入的
script.source内容存在差异(哪怕只是空格、换行、大小写变动),ES都会判定为新脚本触发重新编译。 - 新增2个脚本后,单请求关联的脚本数量增加,若你的业务请求高频发起、且脚本未正确复用缓存,很容易快速触达编译上限。
解决方案
按优先级从高到低推荐以下方案:
方案1:固定脚本模板,全量使用参数传值
你当前的脚本已经是参数化结构,只要保证每次请求的script.source内容完全一致(不要修改模板里的任何字符,包括空格、换行、符号),ES只会在第一次执行时编译1次,后续所有请求直接走缓存,不会触发重复编译。
注意:如果是代码动态生成查询语句,禁止拼接修改source模板内容,所有可变值全部放到params块中传递
方案2:预存脚本(长期最优方案)
将所有用到的Painless脚本提前存储到ES集群,后续查询直接引用脚本ID即可,完全规避动态编译问题:
- 存储脚本示例:
POST _scripts/check_email_active { "script": { "lang": "painless", "source": "if(!doc['email_active'].empty && doc['email_active'].toInstant().toEpochMilli()/(params.divi) >= (params.epochtime)) return 30; return 0;" } }
- 查询时引用脚本:
{ "script_score": { "script": { "id": "check_email_active", "params": { "divi": 1000, "epochtime": 1607863137 } } } }
所有用到的脚本都按上述方式预存储即可,后续迭代只需更新对应ID的脚本内容,查询侧无需修改逻辑。
方案3:临时调整编译阈值(仅应急使用)
如果是业务高峰临时需要快速恢复服务,可以临时调大编译频率阈值,该方案仅为治标手段,不推荐长期使用:
PUT _cluster/settings { "persistent": { "script.max_compilations_rate": "200/5m" } }
内容的提问来源于stack exchange,提问作者Agnivesh Sharma
相关产品推荐
相关产品推荐

