ElasticSearch:禁用Groovy的_score字段上的聚合

时间:2015-05-06 19:59:50

标签: groovy elasticsearch scripting

我在_score字段上进行聚合或与之相关的每个示例(例如,ElasticSearch: aggregation on _score field?)似乎都需要使用脚本。出于安全原因,默认情况下ElasticSearch会禁用动态脚本,有没有办法在不借助将脚本文件加载到每个ES节点或重新启用动态脚本的情况下实现此目的?

我的原始聚合如下所示:

"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安装或配置的一部分,我无法添加或编辑任何内容。

2 个答案:

答案 0 :(得分:0)

一种可能的方法是使用其他可用的脚本选项。除非启用动态脚本,否则似乎无法使用mvel。而且,除非a more fine-grained control of scripting enable/disable达到1.6版本,否则我认为无法为mvel而非groovy启用动态脚本。

我们留有默认启用的nativemustache(用于模板)。我不认为可以使用mustache完成自定义脚本编写,如果可能的话,我找不到方法,我们会留下native(Java)脚本。

以下是我对此的看法:

  • 创建NativeScriptFactory
  • 的实现
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();
    }

}
  • AbstractFloatSearchScript的实现,例如:
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;
    }

}
  • 或者,构建一个简单的Maven项目来将所有内容组合在一起。 pom.xml中:
<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>
  • 构建它并获取生成的jar文件。
  • 将jar放在[ES_folder] / lib
  • 修改elasticsearch.yml并添加 script.native.my_script.type: com.foo.script.MyScriptNativeScriptFactory

  • 重启ES节点。

  • 在聚合中使用它:
{
  "aggs": {
    "max_score": {
      "max": {
        "script": "my_script",
        "lang": "native"
      }
    }
  }
}

上面的示例只返回_score作为脚本,但当然,它可以在更高级的场景中使用。

编辑:如果您不被允许触摸实例,那么我认为您没有任何选择。

答案 1 :(得分:0)

ElasticSearch至少版本1.7.1以及可能更早版本也提供了Lucene的Expression脚本语言的使用 - 并且由于Expression默认使用沙盒,因此它可以像Groovy一样用于动态内联脚本。在我们的情况下,我们的生产ES集群刚刚从1.4.1升级到1.7.1,我们决定不再使用Groovy,因为它具有非沙盒性质,尽管我们仍然希望使用动态脚本,因为随着我们继续微调我们的应用程序及其搜索层,它们易于部署并提供灵活性。

虽然编写本机Java脚本作为动态Groovy函数得分的替代,但在我们的案例中也可能有用,我们想看看使用Expression作为动态内联脚本语言的可行性。阅读完文档后,我发现我们只能在内联"groovy"脚本和"expression"属性中将“lang”属性从function_score更改为script.inline: sandbox.../config/elasticsearch.yml文件中设置 - 功能评分脚本无需任何其他修改即可运行。因此,我们现在可以继续在ElasticSearch中使用动态内联脚本,并在启用沙盒的情况下执行此操作(默认情况下,Expression是沙箱)。显然,还应实施其他安全措施,例如在应用程序代理和防火墙后面运行ES群集,以确保外部用户无法直接访问ES节点或ES API。但是,这是一个非常简单的更改,目前已经解决了Groovy缺少沙盒的问题以及使其无需沙盒运行的担忧。

虽然将动态脚本切换到Expression只能在某些情况下起作用或适用(取决于内联动态脚本的复杂性),但似乎值得分享这些信息,希望它可以帮助其他开发人员。

作为备注,其他支持的ES脚本语言之一,Mustache似乎只能用于在搜索查询中创建模板。它似乎不适用于任何更复杂的脚本需求,例如function_score等,虽然我不确定在第一次阅读更新的ES文档时这是完全明显的。

最后,需要注意的另一个问题是,在最新的ES版本中,Lucene Expression脚本的使用被标记为实验性功能,并且该文档指出,由于此脚本扩展正在经历重大此时的开发工作,其使用或功能可能会在更高版本的ES中发生变化。因此,如果您切换到使用Expression用于任何脚本(动态或其他),则应在文档/开发人员注释中注意,在下次升级ES安装之前重新访问这些更改,以确保脚本保持兼容并以预期

至少对于我们的情况,除非我们愿意允许在最新版本的ES中再次启用非沙盒动态脚本(通过script.inline: on选项),以便内联Groovy脚本可以继续运行,切换到Lucene Expression脚本似乎是目前最好的选择。

在将来的版本中看到ES的脚本选择会发生什么变化会很有趣,特别是考虑到版本2.0将完全删除Groovy的(显然无效的)沙盒选项。希望可以采用其他保护措施来实现动态Groovy的使用,或者Lucene Expression脚本将采用Groovy的位置,并将启用开发人员已经使用的所有类型的动态脚本。

有关Lucene Expression的更多说明,请参阅此处的ES文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html#_lucene_expressions_scripts - 此页面也是有关从ES v2.0 +计划删除Groovy沙盒选项的说明的来源。可以在此处找到Lucene Expression文档:http://lucene.apache.org/core/4_9_0/expressions/index.html?org/apache/lucene/expressions/js/package-summary.html