ElasticSearch:禁用Groovy的_分数字段上的聚合
我看到的每个在_score字段上进行聚合或与之相关的示例(例如)似乎都需要使用脚本。由于安全原因,默认情况下ElasticSearch禁用动态脚本,有没有办法在不向每个ES节点加载脚本文件或重新启用动态脚本的情况下实现这一点 我最初的聚合如下所示:ElasticSearch:禁用Groovy的_分数字段上的聚合,groovy,
elasticsearch,scripting,Groovy,
elasticsearch,Scripting,我看到的每个在_score字段上进行聚合或与之相关的示例(例如)似乎都需要使用脚本。由于安全原因,默认情况下ElasticSearch禁用动态脚本,有没有办法在不向每个ES节点加载脚本文件或重新启用动态脚本的情况下实现这一点 我最初的聚合如下所示: "aggs": { "terms_agg": { "terms": { "field": "field1", "order": {"max_score": "desc"}
"aggs": {
"terms_agg": {
"terms": {
"field": "field1",
"order": {"max_score": "desc"}
},
"aggs": {
"max_score": {
"max": {"script": "_score"}
},
"top_terms": {
"top_hits": {"size": 1}
}
}
}
尝试将表达式指定为lang似乎不起作用,因为ES会抛出一个错误,说明分数只能在用于排序时访问。我想不出还有什么其他方法可以按照分数字段来排序我的桶。有人有什么想法吗
编辑:澄清一下,我的限制是不能修改服务器端。也就是说,作为ES安装或配置的一部分,我无法添加或编辑任何内容。一种可能的方法是使用其他可用的脚本选项<除非启用动态脚本,否则似乎无法使用代码>mvel。而且,除非达到1.6版本,否则我认为不可能为
mvel
和groovy
启用动态脚本
剩下的是默认启用的native
和mustache
(用于模板)。我不认为自定义脚本可以通过mustache
来完成,如果可能的话,我没有找到一种方法,我们只能使用原生的(Java)脚本
以下是我对此的看法:
- 创建
NativeScriptFactory
的实现:
- 或者,构建一个简单的Maven项目来将所有这些联系在一起。pom.xml:
我上面的示例只是将\u分数
作为脚本返回,当然,它可以在更高级的场景中使用
编辑:如果不允许您触摸实例,那么我认为您没有任何选择。ElasticSearch至少在1.7.1版和可能更早的版本中还提供了Lucene的表达式脚本语言的使用,并且由于表达式在默认情况下是沙盒的,所以它可以以与Groovy大致相同的方式用于动态内联脚本。在我们的例子中,我们的生产ES集群刚刚从1.4.1升级到1.7.1,我们决定不再使用Groovy,因为它是非沙盒的,尽管我们仍然希望使用动态脚本,因为在我们继续微调应用程序及其搜索层时,它们提供了易于部署和灵活性
在我们的例子中,编写一个本地Java脚本来替代我们的动态Groovy函数分数可能也是一种可能性,但我们想看看在我们的动态内联脚本语言中使用表达式的可行性。在阅读了文档之后,我发现我们可以简单地将“lang”属性从“groovy”
更改为“expression”
在我们的内联function\u score
脚本中,使用script.inline:sandbox
属性设置在../config/elasticsearch.yml
文件中–function score脚本在没有任何其他修改的情况下工作。因此,我们现在可以继续在ElasticSearch中使用动态内联脚本,并在启用沙盒的情况下使用动态内联脚本(因为默认情况下表达式是沙盒的)。显然,还应实施其他安全措施,如在应用程序代理和防火墙后运行ES群集,以确保外部用户无法直接访问ES节点或ES API。然而,这是一个非常简单的更改,目前已经解决了Groovy缺少沙箱的问题,以及使它能够在没有沙箱的情况下运行的问题
虽然将动态脚本切换到表达式可能只在某些情况下有效或适用(取决于内联动态脚本的复杂性),但似乎值得分享这些信息,希望它能帮助其他开发人员
请注意,作为其他受支持的ES脚本语言之一,Mustach似乎仅可用于在搜索查询中创建模板。它似乎不适用于任何更复杂的脚本需求,如功能评分
,尽管我不确定这在第一次通读更新的ES文档时是否完全清楚
最后,需要注意的另一个问题是,Lucene表达式脚本的使用在最新的ES版本中被标记为实验性功能,并且文档指出,由于此脚本扩展目前正在进行大量的开发工作,其使用或功能可能会在更高版本的ES中发生变化。因此,如果您切换到对任何脚本(动态或其他)使用Expression,则应在您的文档/开发人员说明中注明,以便在下次升级ES安装之前重新查看这些更改,以确保脚本保持兼容并按预期工作
至少在我们的情况下,除非我们愿意在最新版本的ES中再次启用非沙盒动态脚本(通过script.inline:on
选项),以便内联Groovy脚本可以继续运行,否则切换到Lucene表达式脚本似乎是目前最好的选择
在未来的版本中,可以看到ES的脚本选择发生了什么变化,特别是考虑到Groovy的(显然无效的)沙箱选项将在2.0版中完全删除,这将是一件有趣的事情。希望能有其他保护措施来支持动态Groovy的使用,或者Lucene表达式脚本将取代Groovy,并支持开发人员已经在使用的所有类型的动态脚本
有关Lucene表达式的更多说明,请参见此处的ES文档:–本页也是有关计划从ES中删除Groovy沙箱选项的说明的来源
package com.foo.script;
import java.util.Map;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;
public class MyScriptNativeScriptFactory implements NativeScriptFactory {
@Override
public ExecutableScript newScript(Map<String, Object> arg0) {
return new MyScript();
}
}
package com.foo.script;
import java.io.IOException;
import org.elasticsearch.script.AbstractFloatSearchScript;
public class MyScript extends AbstractFloatSearchScript {
@Override
public float runAsFloat() {
try {
return score();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}
<properties>
<elasticsearch.version>1.5.2</elasticsearch.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
{
"aggs": {
"max_score": {
"max": {
"script": "my_script",
"lang": "native"
}
}
}
}