示例文本分析插件

编辑

此示例演示如何使用稳定插件 API 创建简单的“Hello world”文本分析插件。该插件提供一个自定义 Lucene token 过滤器,它会去除所有标记,只保留“hello”和“world”。

Elastic 提供了一个 Gradle 插件,elasticsearch.stable-esplugin,它使开发和打包稳定插件更容易。本指南中的步骤假设您使用此插件。但是,您不需要 Gradle 即可创建插件。

  1. 为您的项目创建一个新目录。
  2. 在此示例中,源代码组织在 maintest 目录下。在项目的根目录中,创建 src/ src/main/src/test/ 目录。
  3. 在项目的根目录中创建以下 build.gradle 构建脚本

    ext.pluginApiVersion = '8.7.0'
    ext.luceneVersion = '9.5.0'
    
    buildscript {
      ext.pluginApiVersion = '8.7.0'
      repositories {
        mavenCentral()
      }
      dependencies {
        classpath "org.elasticsearch.gradle:build-tools:${pluginApiVersion}"
      }
    }
    
    apply plugin: 'elasticsearch.stable-esplugin'
    apply plugin: 'elasticsearch.yaml-rest-test'
    
    esplugin {
      name 'my-plugin'
      description 'My analysis plugin'
    }
    
    group 'org.example'
    version '1.0-SNAPSHOT'
    
    repositories {
      mavenLocal()
      mavenCentral()
    }
    
    dependencies {
    
      //TODO transitive dependency off and plugin-api dependency?
      compileOnly "org.elasticsearch.plugin:elasticsearch-plugin-api:${pluginApiVersion}"
      compileOnly "org.elasticsearch.plugin:elasticsearch-plugin-analysis-api:${pluginApiVersion}"
      compileOnly "org.apache.lucene:lucene-analysis-common:${luceneVersion}"
    
      //TODO for testing this also have to be declared
      testImplementation "org.elasticsearch.plugin:elasticsearch-plugin-api:${pluginApiVersion}"
      testImplementation "org.elasticsearch.plugin:elasticsearch-plugin-analysis-api:${pluginApiVersion}"
      testImplementation "org.apache.lucene:lucene-analysis-common:${luceneVersion}"
    
      testImplementation ('junit:junit:4.13.2'){
        exclude group: 'org.hamcrest'
      }
      testImplementation 'org.mockito:mockito-core:4.4.0'
      testImplementation 'org.hamcrest:hamcrest:2.2'
    
    }
  4. src/main/java/org/example/ 中,创建 HelloWorldTokenFilter.java。此文件提供了去除所有标记(除了“hello”和“world”)的 token 过滤器的代码。

    package org.example;
    
    import org.apache.lucene.analysis.FilteringTokenFilter;
    import org.apache.lucene.analysis.TokenStream;
    import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
    
    import java.util.Arrays;
    
    public class HelloWorldTokenFilter extends FilteringTokenFilter {
        private final CharTermAttribute term = addAttribute(CharTermAttribute.class);
    
        public HelloWorldTokenFilter(TokenStream input) {
            super(input);
        }
    
        @Override
        public boolean accept() {
            if (term.length() != 5) return false;
            return Arrays.equals(term.buffer(), 0, 4, "hello".toCharArray(), 0, 4)
                    || Arrays.equals(term.buffer(), 0, 4, "world".toCharArray(), 0, 4);
        }
    }
  5. 可以使用以下 HelloWorldTokenFilterFactory.java 工厂类将此过滤器提供给 Elasticsearch。@NamedComponent 注解用于为过滤器指定 hello_world 名称。这是您可以用来引用过滤器的名称,前提是插件已部署。

    package org.example;
    
    import org.apache.lucene.analysis.TokenStream;
    import org.elasticsearch.plugin.analysis.TokenFilterFactory;
    import org.elasticsearch.plugin.NamedComponent;
    
    @NamedComponent(value = "hello_world")
    public class HelloWorldTokenFilterFactory implements TokenFilterFactory {
    
        @Override
        public TokenStream create(TokenStream tokenStream) {
            return new HelloWorldTokenFilter(tokenStream);
        }
    
    }
  6. 单元测试可以放在 src/test 目录下。您需要添加首选测试框架的依赖项。
  7. 运行

    gradle bundlePlugin

    这将构建 JAR 文件,生成元数据文件,并将它们捆绑到插件 ZIP 文件中。生成的 ZIP 文件将写入 build/distributions 目录。

  8. 安装插件.
  9. 您可以使用 _analyze API 验证 hello_world token 过滤器是否按预期工作。

    GET /_analyze
    {
      "text": "hello to everyone except the world",
      "tokenizer": "standard",
      "filter":  ["hello_world"]
    }

YAML REST 测试

编辑

如果您使用的是 Gradle 的 elasticsearch.stable-esplugin 插件,则可以使用 Elasticsearch 的 YAML REST 测试框架。此框架允许您在运行的测试集群中加载插件,并针对其发出真实的 REST API 查询。本教程的范围不包含此框架的完整语法,但 Elasticsearch 存储库中有很多示例。有关示例,请参阅 Elasticsearch Github 存储库中的 示例分析插件

  1. src 目录中创建一个 yamlRestTest 目录。
  2. yamlRestTest 目录下,为 Java 源代码创建一个 java 文件夹,并创建一个 resources 文件夹。
  3. src/yamlRestTest/java/org/example/ 中,创建 HelloWorldPluginClientYamlTestSuiteIT.java。此类实现 ESClientYamlSuiteTestCase

    import com.carrotsearch.randomizedtesting.annotations.Name;
    import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
    import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
    import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
    
    public class HelloWorldPluginClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
    
        public HelloWorldPluginClientYamlTestSuiteIT(
                @Name("yaml") ClientYamlTestCandidate testCandidate
        ) {
            super(testCandidate);
        }
    
        @ParametersFactory
        public static Iterable<Object[]> parameters() throws Exception {
            return ESClientYamlSuiteTestCase.createParameters();
        }
    }
  4. src/yamlRestTest/resources/rest-api-spec/test/plugin 中,创建 10_token_filter.yml YAML 文件。

    ## Sample rest test
    ---
    "Hello world plugin test - removes all tokens except hello and world":
      - do:
          indices.analyze:
            body:
              text: hello to everyone except the world
              tokenizer: standard
              filter:
                - type: "hello_world"
      - length: { tokens: 2 }
      - match:  { tokens.0.token: "hello" }
      - match:  { tokens.1.token: "world" }
  5. 使用以下命令运行测试:

    gradle yamlRestTest