Elasticsearch:从零开始创建一个 REST handler 插件

1,363 阅读4分钟

在 Kibana 的 console 中,我们可以使用一些命令对 Elasticsearch 进行交互。那么我们是否可以扩展我们需要的一些命令呢?比如:

在上面,我们打入 GET _cat/example,它将显示右边的输出。这个是我们扩展的一个命令。

Elasticsearch 带有一组可以执行各种任务的功能。 但是,如果你想实现自己的任何功能,则需要在 Elasticsearch 的主代码库中实现。 为了保护你免受所有这些额外步骤的影响,Elasticsearch 提供了在 Elasticsearch 代码中添加插件的选项,该插件能够实现你的功能。

在今天的展示中,我将使用最新的 Elastic Stack 8.4.0 来进行展示。

安装

如果你还没有安装好自己的 Elastic Stack,请参考如下的文章来安装 Elasticsearch 及 Kibana:

创建插件模板

在我之前的文章 

我已经展示了如何为 ingest pipeline 创建 processors。在上面的第二篇文章中,我使用了一个叫做 elasticsearch-plugin-archtype 的插件。我们可以使用如下的命令来创建一个最为基本的插件模板:

1.  mvn archetype:generate \
2.      -DarchetypeGroupId=org.codelibs \
3.      -DarchetypeArtifactId=elasticsearch-plugin-archetype \
4.      -DarchetypeVersion=6.6.0 \
5.      -DgroupId=com.liuxg \
6.      -DartifactId=elasticsearch-plugin \
7.      -Dversion=1.0-SNAPSHOT \
8.      -DpluginName=rest_handler 

上面已经帮我们创建了一个最为基本的插件模板。它在当前的目录下创建了一个叫做 elasticsearch-plugin 的目录。我们首先进入到该目录中:

`

1.  $ pwd
2.  /Users/liuxg/java/plugins/elasticsearch-plugin
3.  $ tree -L 8
4.  .
5.  ├── pom.xml
6.  └── src
7.      └── main
8.          ├── assemblies
9.          │   └── plugin.xml
10.          ├── java
11.          │   └── com
12.          │       └── liuxg
13.          │           ├── rest
14.          │           │   └── Restrest_handlerAction.java
15.          │           └── rest_handlerPlugin.java
16.          └── plugin-metadata
17.              └── plugin-descriptor.properties

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

上面是它的文件结构。因为我们想为 Elastic Stack 8.4.0 构建插件,所以,我们必须在 pom.xml 中修改相应的版本信息:

pom.xml

`

1.  <?xml version="1.0" encoding="UTF-8"?>
2.  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3.  	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.  	<name>elasticsearch-plugin</name>
5.  	<modelVersion>4.0.0</modelVersion>
6.  	<groupId>com.liuxg</groupId>
7.  	<artifactId>elasticsearch-plugin</artifactId>
8.  	<version>1.0-SNAPSHOT</version>
9.  	<packaging>jar</packaging>
10.  	<description>elasticsearch rest_handler plugin</description>
11.  	<inceptionYear>2019</inceptionYear>
12.  	<licenses>
13.  		<license>
14.  			<name>The Apache Software License, Version 2.0</name>
15.  			<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
16.  			<distribution>repo</distribution>
17.  		</license>
18.  	</licenses>
19.  	<properties>
20.  		<elasticsearch.version>8.4.0</elasticsearch.version>
21.  		<elasticsearch.plugin.classname>com.liuxg.rest_handlerPlugin</elasticsearch.plugin.classname>
22.  		<log4j.version>2.11.1</log4j.version>
23.  		<maven.compiler.source>1.8</maven.compiler.source>
24.  		<maven.compiler.target>1.8</maven.compiler.target>
25.  	</properties>
26.  	<build>
27.  		<plugins>
28.  			<plugin>
29.  				<artifactId>maven-compiler-plugin</artifactId>
30.  				<version>3.8.0</version>
31.  				<configuration>
32.  					<source>${maven.compiler.source}</source>
33.  					<target>${maven.compiler.target}</target>
34.  					<encoding>UTF-8</encoding>
35.  				</configuration>
36.  			</plugin>
37.  			<plugin>
38.  				<artifactId>maven-surefire-plugin</artifactId>
39.  				<version>2.22.1</version>
40.  				<configuration>
41.  					<includes>
42.  						<include>**/*Tests.java</include>
43.  					</includes>
44.  				</configuration>
45.  			</plugin>
46.  			<plugin>
47.  				<artifactId>maven-source-plugin</artifactId>
48.  				<version>3.0.1</version>
49.  				<executions>
50.  					<execution>
51.  						<id>attach-sources</id>
52.  						<goals>
53.  							<goal>jar</goal>
54.  						</goals>
55.  					</execution>
56.  				</executions>
57.  			</plugin>
58.  			<plugin>
59.  				<artifactId>maven-assembly-plugin</artifactId>
60.  				<version>3.1.0</version>
61.  				<configuration>
62.  					<appendAssemblyId>false</appendAssemblyId>
63.  					<outputDirectory>${project.build.directory}/releases/</outputDirectory>
64.  					<descriptors>
65.  						<descriptor>${basedir}/src/main/assemblies/plugin.xml</descriptor>
66.  					</descriptors>
67.  				</configuration>
68.  				<executions>
69.  					<execution>
70.  						<phase>package</phase>
71.  						<goals>
72.  							<goal>single</goal>
73.  						</goals>
74.  					</execution>
75.  				</executions>
76.  			</plugin>
77.  		</plugins>
78.  	</build>
79.  	<dependencies>
80.  		<dependency>
81.  			<groupId>org.elasticsearch</groupId>
82.  			<artifactId>elasticsearch</artifactId>
83.  			<version>${elasticsearch.version}</version>
84.  			<scope>provided</scope>
85.  		</dependency>
86.  		<dependency>
87.  			<groupId>org.apache.logging.log4j</groupId>
88.  			<artifactId>log4j-api</artifactId>
89.  			<version>${log4j.version}</version>
90.  			<scope>provided</scope>
91.  		</dependency>
92.  	</dependencies>
93.  </project>

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

在上面,我们把 elasticsearch.version 设置为 8.4.0。其它的保持不变。

接下来,我们来修改 rest_handlerPlugin.java 文件:

rest_handlerPlugin.java

`

1.  package com.liuxg;

3.  import java.util.List;
4.  import java.util.function.Supplier;

6.  import com.liuxg.rest.Restrest_handlerAction;
7.  import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
8.  import org.elasticsearch.cluster.node.DiscoveryNodes;
9.  import org.elasticsearch.common.settings.ClusterSettings;
10.  import org.elasticsearch.common.settings.IndexScopedSettings;
11.  import org.elasticsearch.common.settings.Settings;
12.  import org.elasticsearch.common.settings.SettingsFilter;
13.  import org.elasticsearch.plugins.ActionPlugin;
14.  import org.elasticsearch.plugins.Plugin;
15.  import org.elasticsearch.rest.RestController;
16.  import org.elasticsearch.rest.RestHandler;

18.  import static java.util.Collections.singletonList;

20.  public class rest_handlerPlugin extends Plugin implements ActionPlugin {
21.      @Override
22.      public List<RestHandler> getRestHandlers(final Settings settings,
23.                                               final RestController restController,
24.                                               final ClusterSettings clusterSettings,
25.                                               final IndexScopedSettings indexScopedSettings,
26.                                               final SettingsFilter settingsFilter,
27.                                               final IndexNameExpressionResolver indexNameExpressionResolver,
28.                                               final Supplier<DiscoveryNodes> nodesInCluster) {
29.          return singletonList(new Restrest_handlerAction());
30.      }
31.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

这个文件会让 Elasticsearch 知道你的插件。

我们接下来修改 Restrest_handlerAction.java 文件如下:

Restrest_handlerAction.java

`

1.  package com.liuxg.rest;

3.  import org.elasticsearch.client.internal.node.NodeClient;
4.  import org.elasticsearch.common.Table;
5.  import org.elasticsearch.rest.RestRequest;
6.  import org.elasticsearch.rest.RestResponse;
7.  import org.elasticsearch.rest.action.cat.AbstractCatAction;
8.  import org.elasticsearch.rest.action.cat.RestTable;

10.  import java.util.List;

12.  import static org.elasticsearch.rest.RestRequest.Method.GET;
13.  import static org.elasticsearch.rest.RestRequest.Method.POST;

16.  public class Restrest_handlerAction extends AbstractCatAction {
17.      @Override
18.      public List<Route> routes() {
19.          return List.of(
20.                  new Route(GET, "/_cat/example"),
21.                  new Route(POST, "/_cat/example"));
22.      }

24.      @Override
25.      public String getName() {
26.          return "rest_handler_cat_example";
27.      }

29.      @Override
30.      protected RestChannelConsumer doCatRequest(final RestRequest request, final NodeClient client) {
31.          final String message = request.param("message", "Hello from Cat Example action");

33.          Table table = getTableWithHeader(request);
34.          table.startRow();
35.          table.addCell(message);
36.          table.endRow();
37.          return channel -> {
38.              try {
39.                  channel.sendResponse(RestTable.buildResponse(table, channel));
40.              } catch (final Exception e) {
41.                  channel.sendResponse(new RestResponse(channel, e));
42.              }
43.          };
44.      }

46.      @Override
47.      protected void documentation(StringBuilder sb) {
48.          sb.append(documentation());
49.      }

51.      public static String documentation() {
52.          return "/_cat/example\n";
53.      }

55.      @Override
56.      protected Table getTableWithHeader(RestRequest request) {
57.          final Table table = new Table();
58.          table.startHeaders();
59.          table.addCell("test", "desc:test");
60.          table.endHeaders();
61.          return table;
62.      }
63.  }

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

该文件将定义插件的路由和处理这些路由的代码。

这样我们就修改完了我们的代码。

编译

我们在项目的根目录下使人如下的命令来进行编译:

mvn clean install
`

1.  $ mvn clean install
2.  [INFO] Scanning for projects...
3.  [INFO] 
4.  [INFO] -------------------< com.liuxg:elasticsearch-plugin >-------------------
5.  [INFO] Building elasticsearch-plugin 1.0-SNAPSHOT
6.  [INFO] --------------------------------[ jar ]---------------------------------
7.  [INFO] 
8.  [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ elasticsearch-plugin ---
9.  [INFO] 
10.  [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ elasticsearch-plugin ---
11.  [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
12.  [INFO] skip non existing resourceDirectory /Users/liuxg/java/plugins/elasticsearch-plugin/src/main/resources
13.  [INFO] 
14.  [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ elasticsearch-plugin ---
15.  [INFO] Changes detected - recompiling the module!
16.  [INFO] Compiling 2 source files to /Users/liuxg/java/plugins/elasticsearch-plugin/target/classes
17.  [INFO] 
18.  [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ elasticsearch-plugin ---
19.  [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
20.  [INFO] skip non existing resourceDirectory /Users/liuxg/java/plugins/elasticsearch-plugin/src/test/resources
21.  [INFO] 
22.  [INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ elasticsearch-plugin ---
23.  [INFO] No sources to compile
24.  [INFO] 
25.  [INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ elasticsearch-plugin ---
26.  [INFO] No tests to run.
27.  [INFO] 
28.  [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ elasticsearch-plugin ---
29.  [INFO] Building jar: /Users/liuxg/java/plugins/elasticsearch-plugin/target/elasticsearch-plugin-1.0-SNAPSHOT.jar
30.  [INFO] 
31.  [INFO] >>> maven-source-plugin:3.0.1:jar (attach-sources) > generate-sources @ elasticsearch-plugin >>>
32.  [INFO] 
33.  [INFO] <<< maven-source-plugin:3.0.1:jar (attach-sources) < generate-sources @ elasticsearch-plugin <<<
34.  [INFO] 
35.  [INFO] 
36.  [INFO] --- maven-source-plugin:3.0.1:jar (attach-sources) @ elasticsearch-plugin ---
37.  [INFO] Building jar: /Users/liuxg/java/plugins/elasticsearch-plugin/target/elasticsearch-plugin-1.0-SNAPSHOT-sources.jar
38.  [INFO] 
39.  [INFO] --- maven-assembly-plugin:3.1.0:single (default) @ elasticsearch-plugin ---
40.  [INFO] Reading assembly descriptor: /Users/liuxg/java/plugins/elasticsearch-plugin/src/main/assemblies/plugin.xml
41.  [WARNING] The following patterns were never triggered in this artifact exclusion filter:
42.  o  'org.elasticsearch:elasticsearch'

44.  [INFO] Building zip: /Users/liuxg/java/plugins/elasticsearch-plugin/target/releases/elasticsearch-plugin-1.0-SNAPSHOT.zip
45.  [INFO] 
46.  [INFO] --- maven-install-plugin:2.4:install (default-install) @ elasticsearch-plugin ---
47.  [INFO] Installing /Users/liuxg/java/plugins/elasticsearch-plugin/target/elasticsearch-plugin-1.0-SNAPSHOT.jar to /Users/liuxg/.m2/repository/com/liuxg/elasticsearch-plugin/1.0-SNAPSHOT/elasticsearch-plugin-1.0-SNAPSHOT.jar
48.  [INFO] Installing /Users/liuxg/java/plugins/elasticsearch-plugin/pom.xml to /Users/liuxg/.m2/repository/com/liuxg/elasticsearch-plugin/1.0-SNAPSHOT/elasticsearch-plugin-1.0-SNAPSHOT.pom
49.  [INFO] Installing /Users/liuxg/java/plugins/elasticsearch-plugin/target/elasticsearch-plugin-1.0-SNAPSHOT-sources.jar to /Users/liuxg/.m2/repository/com/liuxg/elasticsearch-plugin/1.0-SNAPSHOT/elasticsearch-plugin-1.0-SNAPSHOT-sources.jar
50.  [INFO] Installing /Users/liuxg/java/plugins/elasticsearch-plugin/target/releases/elasticsearch-plugin-1.0-SNAPSHOT.zip to /Users/liuxg/.m2/repository/com/liuxg/elasticsearch-plugin/1.0-SNAPSHOT/elasticsearch-plugin-1.0-SNAPSHOT.zip
51.  [INFO] ------------------------------------------------------------------------
52.  [INFO] BUILD SUCCESS
53.  [INFO] ------------------------------------------------------------------------
54.  [INFO] Total time:  5.352 s
55.  [INFO] Finished at: 2022-09-06T10:55:38+08:00
56.  [INFO] ------------------------------------------------------------------------

`![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)

编译成功后,我们可以在 targe 目录先看到如下的安装文件:



1.  $ pwd
2.  /Users/liuxg/java/plugins/elasticsearch-plugin
3.  $ ls target/releases
4.  elasticsearch-plugin-1.0-SNAPSHOT.zip


上面显示的 elasticsearch-plugin-1.0-SNAPSHOT.zip 就是我们可以安装的插件文件。

安装插件并测试插件

我们接下来换到 Elasticsearch 的安装目录下,并打入如下的命令:



1.  $ pwd
2.  /Users/liuxg/elastic0/elasticsearch-8.4.0
3.  $ bin/elasticsearch-plugin install file:Users/liuxg/java/plugins/elasticsearch-plugin/target/releases/elasticsearch-plugin-1.0-SNAPSHOT.zip
4.  -> Installing file:Users/liuxg/java/plugins/elasticsearch-plugin/target/releases/elasticsearch-plugin-1.0-SNAPSHOT.zip
5.  -> Downloading file:Users/liuxg/java/plugins/elasticsearch-plugin/target/releases/elasticsearch-plugin-1.0-SNAPSHOT.zip
6.  [=================================================] 100%   
7.  -> Installed rest_handler
8.  -> Please restart Elasticsearch to activate any plugins installed
9.  $ ./bin/elasticsearch-plugin list
10.  rest_handler


从上面的显示中,我们可以看出来 rest_handler 插件已经被成功地安装。我们接下来需要重新启动 Elasticsearch。这个非常重要!

我们打开 Kibana,并打入如下的命令:

我们也可以直接在 terminal 中打入如下的命令:

curl -k --user elastic:V_USqc1cWM40W_pIHnni https://localhost:9200/_cat/example


1.  $ curl -k --user elastic:V_USqc1cWM40W_pIHnni https://localhost:9200/_cat/example
2.  Hello from Cat Example action


 整个项目的代码可以在地址下载:GitHub - liu-xiao-guo/rest_handler_plugin

参考:

【1】elasticsearch/plugins/examples at main · elastic/elasticsearch · GitHub