一、插件简介

Elasticseaarch提供插件的方式来让更多的开发者来增强Elasticsearch的功能,Elasticsearch中的插件分为两个大的分类:

  • 核心插件

由Elasticsearch内部开发人员开发提供以增强某些功能

  • 社区贡献

由第三方开发者或企业开发以插件的形式集成到Elasticsearch
本文结合hanlp,将hanlp的汉字转拼音方法,封装为es的插件,es插件依赖于es,因此每个版本的es都需要开发对应版本的插件,此次测试使用的是es6.5.4

二、插件类型详解

Es官方文档对于es插件的开发没有直接相关的文档,但提供了事例插件的源代码,可直接通过阅读源代及其注释获取相关信息
Elasticsearch的插件处理都在org.elasticsearch.plugins包下,核心接口为Plugin,我们先预览下该接口的核心源码
/
An extension point allowing to plug in custom functionality. This class has a number of extension points that are available to all plugins, in addition you can implement any of the following interfaces to further customize Elasticsearch:
{@link ActionPlugin}
{@link AnalysisPlugin}
{@link ClusterPlugin}
{@link DiscoveryPlugin}
{@link IngestPlugin}
{@link MapperPlugin}
{@link NetworkPlugin}
{@link RepositoryPlugin}
{@link ScriptPlugin}
{@link SearchPlugin}

In addition to extension points this class also declares some {@code @Deprecated} {@code public final void onModule} methods. These
methods should cause any extensions of {@linkplain Plugin} that used the pre-5.x style extension syntax to fail to build and point the
plugin author at the new extension syntax. We hope that these make the process of upgrading a plugin from 2.x to 5.x only mildly painful. /
public abstract class Plugin implements Closeable** {

//省略接口方法
}
从核心接口Plugin上可以看出,Elasticsearch支持哪些核心插件的,如下
1. ActionPlugin
Restful API命令请求插件,如果Elasticsearch内置的命令如_all,cat,/cat/health等rest命令无法满足需求,开发者可以自己开发需要的rest命令.

  1. AnalysisPlugin
    分析插件,用于开发者开发额外的分析功能来增强Elasticsearch自身分析功能的不足.

  2. ClusterPlugin
    集群管理插件,用于加强自定义对集群的管理功能

  3. DiscoveryPlugin
    自定义发现插件

  4. IngestPlugin
    预处理插件

  5. MapperPlugin
    映射插件,加强ES的数据类型.比如增加一个attachment类型,里面可以放PDF或者WORD数据

  6. NetworkPlugin
    网络传输插件插件,

  7. RepositoryPlugin
    存储插件,提供快照和恢复

  8. ScriptPlugin
    脚本插件.这个插件本质来说,就是会调用用户的脚本,所以可以执行任何的程序,举例的话,可以通过这个插件,支持javascript语言,python语言,也可以是用户自定义的任何语言或者程序

  9. SearchPlugin
    查询插件,扩展Elasticsearch的查询功能

三、具体开发过程

1.准备工作

本例使用ActionPlugin,开发一个新的断点 _hysz/py来实现es中汉字转拼音的功能

1.1创建maven项目

使用eclipse来新建一个maven项目,大体目录结构如下
elasticsearch插件开发 - 图1

1.2 配置pom.xml

Pom.xml配置信息,主要用到了elasticsearch,hanlp,以及fastjson

4.0.0
com.hysz.elasticsearch.plugins
hysz-plugin
0.0.3
hysz-plugin
hysz-plugin


UTF-8
UTF-8

1.8
1.8
6.5.4
3.6.0

${basedir}/src/main/assemblies/plugin.xml

portable-1.7.2
1.8
1.8



org.elasticsearch
elasticsearch
${elasticsearch.version}
provided


com.hankcs
hanlp
${hanlp.version}








com.alibaba
fastjson
1.2.58





org.apache.maven.plugins
maven-compiler-plugin
${maven.compiler.plugin.version}

${maven.compiler.target}
${maven.compiler.target}



org.apache.maven.plugins
maven-assembly-plugin

false
${project.build.directory}/releases/

${elasticsearch.assembly.descriptor}




package

attached






1.3 配置插件的描述文件(必须)

每一个es插件都需要一个plugin-descriptor.properties 来对插件的信息来进行描述,scr / main / resources中创建plugin-descriptor.properties文件
description=${project.description}
version=${project.version}
name=${project.artifactId}
classname=com.hysz.elasticsearch.plugin.ExampleRestHandlerPlugin //程序的主方法全类名
java.version=1.8 //Java版本
elasticsearch.version=${elasticsearch.version}
// 使用elastic search版本

1.4 配置项目打包信息

src / main / assemblies中创建plugin.xml文件,该文件 将用于配置插件的打包。
<?xml version=“1.0”?>

plugin

zip

false


target
/

*.jar





${project.basedir}/src/main/resources/plugin-descriptor.properties
/
true


${project.basedir}/src/main/resources/plugin-security.policy
/
false




/
false


1.5 配置es的安全策略文件

当插件需要读取文件等一些特殊权限时,还需要添加插件安全策略文件
scr / main / resources中创建plugin-security.policy文件
并添加以下内容:
grant {
permission java.io.FilePermission “<>”, “read,write,delete”;
permission java.util.PropertyPermission ““, “read,write”;
permission java.lang.RuntimePermission “setContextClassLoader”;
permission java.lang.RuntimePermission “getClassLoader”;
permission java.net.SocketPermission “
“, “connect,resolve”;
};
这里面配置的是对es插件的一些特殊权限的授权操作
此步操作非必须,当插件涉及的内容不涉及到一些java特殊权限时,无需配置,保证插件运行时可以得到正常运行的最低权限即可

至此,开发插件的准备工作已经完成,接下来开始创建插件类

2.插件类的开发

1.启动类

创建新端点时,必须扩展类 org.elasticsearch.rest.BaseRestHandler
创建一个启动插件的类 创建一个类继承Plugin
public class ExampleRestHandlerPlugin extends Plugin implements ActionPlugin
之后重写方法getRestHandlers在主方法中得到自定义的新插件端点 _hysz/py
@Override
public List getRestHandlers(final Settings settings,
final RestController restController,
final ClusterSettings clusterSettings,
final IndexScopedSettings indexScopedSettings,
final SettingsFilter settingsFilter,
final IndexNameExpressionResolver indexNameExpressionResolver,
final Supplier nodesInCluster) {
Pyction Pyction = new Pyction(settings, restController);
return singletonList(Pyction); // 添加一个rest处理程序
}

2.新断点功能类

创建一个类来继承AbstractCatAction
public class Pyction extends AbstractCatAction

2.1创建新的端点

在此类中创建一个新的端点
Pyction(final Settings settings, final RestController controller) {
super(settings);
controller.registerHandler(POST, “/_hysz/py”, this);
}
由此,创建了一个post请求的端点

2.2响应端点

@Override
protected RestChannelConsumer doCatRequest(final RestRequest request, final NodeClient client)
在此方法中,写我们的逻辑进行端点的响应
// 获取处理参数
String name = request.param(“text”); // 先获取连接上的参数 如192.168.1.101:9200/_hysz/py?text=”测试内容”
if (name == null && request.content().length() > 0) { // 获取body里的参数 如
POST /_hysz/py
{
“text”:
“我来测试一下”
}
@SuppressWarnings(“deprecation”)
Map map = XContentHelper.convertToMap(request.content(), false).v2();
if (map.containsKey(“text”)) {
name = (String) map.get(“text”);
}
}

  1. String finalName = name;<br /> **return** channel -> {<br /> Messages message = **new** Messages(finalName);<br /> XContentBuilder builder = channel.newBuilder();<br /> builder.startObject();<br /> message.toXContent(builder, request);<br /> builder.endObject();<br /> channel.sendResponse(**new** BytesRestResponse(RestStatus.**_OK_**, builder));<br /> };

3.具体的业务逻辑

//获取需要返回的结果
class Messages implements ToXContent {
private final List text;
Map> pyjson=new HashMap<>();
public Messages(String text) throws IOException {
if (text == null) {
this.text = new ArrayList<>();
} else {
this.text =
AccessController.doPrivileged
((PrivilegedAction>) () ->
{
//XContentBuilder source=null;
List pinyinlist;
pinyinlist= HanLP.convertToPinyinList(text);
Predefine.HANLP_PROPERTIES_PATH = System.getProperties().get(“user.dir”)+”/config/hysz/hanlp.properties”;
return pinyinlist;

});
}
}
// 构建返回结果
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field(“result”, text);
return builder;
}
}

上述代码中的HanLP.convertToPinyinList(text)时hanlp对汉字转拼音方法的一个封装,其中使用了字典,因此需要读取文件的权限,在准备环中,我们已经准备了java安全策略文件进行相关权限的授权,在涉及到特殊权限的代码块中,也需要
AccessController.doPrivileged(
//敏感操作
);
来进行

3.一些存在的问题

3.1 hanlp配置文件的问题

要使用hanlp需要hanlp.properties,来配置各类字典的位置,但是无论此配置文件放在什么位置,在插件运行时都找不到此配置文件,通过查看hanlp的源代码,找到了相关定义配置此文件的方法,因此在代码中使用了
Predefine.HANLP_PROPERTIES_PATH = System.getProperties().get(“user.dir”)+”/config/hysz/hanlp.properties”;
来定义位置,为了统一管理修改,我们默认把他放到es安装目录下的config目录下

3.2 返回结果的格式

测试了一些返回结果支持的格式如下
//返回字符串
final String message = request.param(“message”, “Hello hysz”);
final String message2 = request.param(“message2”, “Hello hyszmessages”);
Table table = getTableWithHeader(request);
table.startRow();
table.addCell(message);
// table.addCell(message2); 这里添加多个报错can’t add more cells to a row than the header
table.endRow();

table.startRow(); // 可以输出两行信息,输出格式为字符串 Hello hysz Hello hyszmessages

table.addCell(message2);
table.endRow();

//返回json格式结果

  1. XContentBuilder builder = channel.newBuilder();// XContentBuilder 用于构建XContent(即 json)的实用程序。<br /> builder.startObject();<br /> builder.field( "message2", "hello hysz");<br /> builder.array( "array", "1,2,3" );<br /> builder.array( "int", new int[]{1,2,3});<br /> message.toXContent( builder, request);<br /> builder.endObject();<br /> 返回格式<br />{<br /> "message2": "hello hysz",<br /> "array": [<br /> "1,2,3"<br /> ],<br /> "int": [<br /> 1,<br /> 2,<br /> 3<br /> ],<br /> "message": "Plugin to support the hysz index."<br />}

四、打包及发布

1.打包

到项目的工作空间目录下,打开命令窗口,使用命令
Mvn clean install 进行maven项目的打包
elasticsearch插件开发 - 图2
打包成功后在\target\releases目录下会生成我们的插件安装包
elasticsearch插件开发 - 图3

2.发布

将打包好的jar上传到非es plugins目录,上传到此目录时,安装插件的过程会报错

如我们上传到/home/soft目录下
进入到es 安装目录下的bin目录,使用命令
./elasticsearch-plugin install file:///home/soft/hysz-plugin-0.0.3.zip 进行插件安装
elasticsearch插件开发 - 图4
安装过程中会打印出我们在准备的java安全策略文件中所配置的所有权限,当我们确认这些权限可以授予此插件时,即可继续安装
安装完成后,在es的plugins目录下即可查看此插件
elasticsearch插件开发 - 图5

3.hanlp相关配置

前面提到了使用Predefine.HANLP_PROPERTIES_PATH = System.getProperties().get(“user.dir”)+”/config/hysz/hanlp.properties”;来规定hanlp描述文件的位置,因此,我们需要在对用的文件夹下放置此文件
elasticsearch插件开发 - 图6
文件大体内容
# Root path of data
root=/home/soft/elasticsearch-6.5.4/plugins/analysis-hanlp
# Core dictionary path
CoreDictionaryPath=data/dictionary/CoreNatureDictionary.txt
用来配置各类词典的具体路径
我们只需要把hanlp词典放到指定位置即可
在此事例中,我们pom.xml中引用的是hanlp一个自带字典的jar包,因此无需另外配置字典也可正常运行,如果使用原始jar包,则必须配置

4.结果测试

elasticsearch插件开发 - 图7
测试成功