変わり種プラグインの
作り方
黒澤亮二
自己紹介
• 黒澤亮二 @rjkuro
• 日本IBM
• データベース周辺の製品開発
• Elasticsearch暦 1年
• 最近の興味:
分散データベース
NoSQL
Search/Analysis
disclaimer
• 嘘知識を聴く可能性があります
• 聞き間違いだと思ってください
• 資料は後からこっそり直す可能性があります
• 本資料は私自身の見解であり、必ずしも私の所属
する組織の立場、戦略、意見を代表するものでは
ありません。
本日の主張
つくれるよ
いろんな
プラグイン
Elasticsearchはプラグイ
ンで機能を追加できる
既存のたくさんあるし
簡単につくれるよ
maven
bin/plugin --install myplugin --url file:///test/myplugin.zip
pom.xml
es-plugin.properties
plugin.xml
MyPlugin.java
MyModule.java
myplugin.zip
プラグイン作れると
いいことあるよ
アプリ Elasticsearch
アプリでの処理を…
プラグイン作れると
いいことあるよ
アプリ Elasticsearch
Elasticsearchノードで動かせる!!
スケールする!
アプリ Elasticsearch Elasticsearch
Elasticsearch Elasticsearch
スケールする!!
アプリ Elastic Elastic Elastic
Elastic Elastic Elastic
Elastic Elastic Elastic
スケールする!!!
アプ
リ
いろいろできるよ
モジュールで「登録メソッド」をよんで
新機能を差しこめる!
Riverプラグインはこれ
Analyzerプラグインはこれ
https://www.found.no/foundation/elasticsearch-internals/
登録メソッドたくさん!
AnalysisModule.addTokenizer(String name, Class<? extends TokenizerFactory> tokenizer)
AnalysisModule.addTokenFilter(String name, Class<? extends TokenFilterFactory>
tokenFilter)
AnalysisModule.addCharFilter(String name, Class<? extends CharFilterFactory> charFilter)
AnalysisModule.addAnalyzer(String name, Class<? extends AnalyzerProvider> analyzer)
RestController.registerHandler(RestRequest.Method method, String path, RestHandler
handler)
RestModule.addRestAction(Class<? extends BaseRestHandler> restAction)
DocumentMapperParser.putTypeParser(String type, Mapper.TypeParser typeParser)
HighlightModule.registerHighlighter(Class<? extends Highlighter> clazz)
IndicesLifecycle.addListener(Listener listener)
IndexQueryParserModule.addQueryParser(String name, Class<? extends QueryParser>
queryParser)
プラグイン専用ではなく
Elasticsearch本体も使ってます
プラグインから
登録メソッド
どうやって呼ぶか?
1. es-plugin.propertiesに自分のPluginクラ
ス名を書く
2. Pluginクラスで自分のModuleクラスを登
録(onModuleがあればここで登録メソッ
ドを呼べる場合も)
3. 自分のModuleクラスのconfigure()に自
分のコンポーネントの生成方法を指定
4. コンポーネントのクラスのコンストラクタ
に@injectionをつける
5. コンストラクタの引数にほしいものを書く
6. 受け取ったものを使って登録メソッドを
呼ぶ
1. es-plugin.propertiesに自分のPluginクラ
ス名を書く
2. Pluginクラスで自分のModuleクラスを登
録(onModuleがあればここで登録メソッ
ドを呼べる場合も)
3. 自分のModuleクラスのconfigure()に自
分のコンポーネントの生成方法を指定
4. コンポーネントのクラスのコンストラクタ
に@injectionをつける
5. コンストラクタの引数にほしいものを書く
6. 受け取ったものを使って登録メソッドを
呼ぶ
→ 例で
例 Mapper プラグイン
Mapperモジュール
plugin=myplugin.MyPlugin
public class MyPlugin extends AbstractPlugin {
public Collection<Class<? extends Module>> indexModules() {
Collection<Class<? extends Module>>
modules = Lists.newArrayList();
modules.add(MyMapperModule.class);
return modules;
}
…
…
私のプラグインのクラス名
私のモジュールを登録
es-plugin.properties
public class MyMapperModule extends AbstractModule {
@Override
protected void configure() {
bind(MyMapperComponent.class).asEagerSingleton();
}
}
public class MyMapperComponent
extends AbstractIndexComponent {
@Inject
public MyMapperComponent(Index index,
@IndexSettings Settings indexSettings,
MapperService mapperService) {
super(index, indexSettings);
mapperService.documentMapperParser()
.putTypeParser("my_type",
new MyMapper.TypeParser());
}
}
「私のクラスを起動時に生成してよー」
欲しいものを
渡してもらって
登録メソッドが呼べた
ここでGuiceのおまじないをすると…
使いみちは、
Index時の事前処理とか
PUT /test/person/1
{
"my_content" : "... 長い文章 ..."
}
{
“content” : “... 処理済の文章 ...",
}
解析処理をしてフィール
ド追加とかできる!
PUT /test/person/1
{
"my_content" : "... 長い文章 ..."
}
{
"content" : "... 長い文章 ...",
"language" : "ja",
"classification" : "essay",
"sentiment" : "positive",
"advertised_products" : { ... }
…
}
なにか既視感?
元ネタは
attachmentプラグイン
PUT /test/person/1
{
"my_attachment" : "... base64 ..."
}
{
"my_attachment.title" : ".…",
"my_attachment.date" : "...",
"my_attachment.author" : "….",
"my_attachment.keywords" : "…",
"my_attachment.content_type" : "…",
"
…
}
というわけで詳しくは:
https://github.com/elastic/elasticsearch-mapper-attachments
例2:Custom query parser
Queryモジュール
使いみち
• Matchクエリ/Query Stringクエリでは物足りない場
合
• スコアを細かく制御したい場合
• インデックスに特殊な構造を持たせてそれを検索
に利用したい場合
→ 自前のシンタックスを実装したり
LuceneのQuery自体をカスタムして利用できる
登録メソッドを持ったオブジェクト
が渡されてくる楽なパターン
public class MyPlugin extends AbstractPlugin {
public void onModule(IndexQueryParserModule module) {
module.addQueryParser("my_query",
MyQueryParser.class);
}
…
…
登録メソッドここで呼べちゃう
public class MyQueryParser implements QueryParser {
public Query parse(QueryParseContext parseContext)
throws IOException, QueryParsingException {
XContentParser parser = parseContext.parser();
Token curToken = parser.currentToken();
…
… トークンをパースしてQueryを返す処理 …
…
Luceneの
オブジェク
トを返せる
例その3:Lifecycleイベント処理
Indicesモジュール
IndicesLifecycleインターフェース
イベントを
フックして処理を挿入できる!
- インデックスやシャードの
open/closeの前後
- シャード移動の前後など
public class MyLifeCycleModule extends AbstractModule {
@Override
protected void configure() {
bind(MyLifeCycleComponent.class).asEagerSingleton();
}
} 「私のクラスを(ry 」
public class MyLifecycleComponent extends AbstractComponent
{
@Inject public MyLifecycleComponent(Settings settings,
IndicesLifecycle indicesLifecycle) {
super(settings);
indicesLifecycle.addListener(
new IndicesLifecycle.Listener() {
@Override
public void
afterIndexCreated(IndexService indexService) {
… indexがopenされたときの処理 …
}
登録メソッド
まとめ
• プラグインは使うだけじゃない
• いろいろ作れる
• スケールさせやすい
• Guiceが欲しいオブジェクトを渡してくれる
• ストアドプロシージャー的な使い方もありかも
参考資料
プラグイン一般
https://www.found.no/foundation/elasticsearch-
internals/
https://www.found.no/foundation/writing-a-plugin/
Attachment mapper plugin
https://github.com/elastic/elasticsearch-mapper-
attachments
Elasticsearch reference
https://www.elastic.co/guide/en/elasticsearch/reference
/1.5/index.html

Elasticsearch 変わり種プラグインの作り方