# Dec 2nd, 2017: \[JP\]Elasticsearch\] Elasticsearch Ingest pluginの作り方

**URL:** <https://discuss.elastic.co/t/dec-2nd-2017-jp-elasticsearch-elasticsearch-ingest-plugin/109307>\
**Category:** Advent Calendar\
**Created:** [December 2, 2017, 12:00am UTC](https://discuss.elastic.co/t/dec-2nd-2017-jp-elasticsearch-elasticsearch-ingest-plugin/109307 "2017-12-02T00:00:04Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![johtani](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/johtani/32/44956_2.png) [@johtani](https://discuss.elastic.co/u/johtani)\
**Post date:** [December 2, 2017, 12:00am UTC](https://discuss.elastic.co/t/dec-2nd-2017-jp-elasticsearch-elasticsearch-ingest-plugin/109307/1 "2017-12-02T00:00:04Z")

</div>

[Ingest Nodeの機能](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)は5で追加されました。Elasticsearchにデータを送信し、インデックスに登録する前処理として、色々な処理が可能です。例えば、Grok pluginを利用すれば、正規表現を利用して文字列を構造化したりできます。また、GeoIP pluginを利用すれば、IPアドレスを元に、緯度経度などの地理情報を追加するといったことも前処理で可能です。

## 独自のIngest Node pluginを作ってみる

Elasticsearchはまた、色々な機能をプラグインとして追加可能です。  
そんなプラグインを独自に作成することもできます。  
ということで、Ingest pluginを簡単につくる方法を今日は紹介します。

### 前提条件

ローカルにcookiecutterコマンドがインストールされていること。  
cookiecutterのインストールについては[こちら](https://cookiecutter.readthedocs.io/en/latest/readme.html)をご覧ください。

### cookiecutterはプロジェクトテンプレート

以下を実行すれば、あとは対話形式で決めていくだけになります。  
今回は、サンプルとして、`hello`というフィールドに`world!`という値を追加するようなサンプルのIngest Processorを作成してみます。

```auto
cookiecutter gh:spinscale/cookiecutter-elasticsearch-ingest-processor

```

決める内容としては、以下の4つです。

- processor\_type
  - Processorの名前

- description
  - このProcessorが何を行うかという説明

- developer\_name
  - あなたのお名前

- elasticsearch\_version
  - 対象とするElasticsearchのバージョン

サンプルの名前を"helloworld"としてみます。

```auto
processor_type [awesome]: helloworld
package_dir [helloworld]: 
description [Ingest processor that is doing something awesome]: Ingest processor that add "hello" field               
developer_name [YOUR REAL NAME]: Jun Ohtani
elasticsearch_version [6.0.0]: 

```

`processor_type`は全て小文字のアルファベットでなければいけないという制約があります。  
上記を入力し終われば、プロジェクトのディレクトリが出来上がります。

実際に作成されたプロジェクトの構成は次のようになります。

> **ディレクトリ構成はこちら**
>
> ```auto
> ingest-helloworld/
> ├── LICENSE.txt
> ├── NOTICE.txt
> ├── README.md
> ├── build.gradle
> ├── settings.gradle
> └── src
> ├── main
> │ ├── java
> │ │ └── org
> │ │ └── elasticsearch
> │ │ └── plugin
> │ │ └── ingest
> │ │ └── helloworld
> │ │ ├── HelloworldProcessor.java
> │ │ └── IngestHelloworldPlugin.java
> │ └── plugin-metadata
> │ └── plugin-security.policy
> └── test
> ├── java
> │ └── org
> │ └── elasticsearch
> │ └── plugin
> │ └── ingest
> │ └── helloworld
> │ ├── HelloworldProcessorTests.java
> │ └── HelloworldRestIT.java
> └── resources
> └── rest-api-spec
> └── test
> └── ingest-helloworld
> ├── 10_basic.yml
> └── 20_helloworld_processor.yml
> 
> ```

ご覧のようにGradleの設定ファイルなども用意されます。  
`src/main`の下にJavaのクラスが、`src/test`の下にテストクラスの雛形が出来上がります。

## Helloworld Processor Pluginの実装

HelloworldProcessor.javaが、実際にIngestで処理したいものを記述します。  
今回のサンプルでは、Ingest Processorの設定として、以下のものを用意します。

- target\_field
  - 追加するフィールド名。デフォルトは`hello`

- target\_value
  - `target_field`に入れる値。デフォルトは`world!`

Processorの設定はFactoryクラスの`create`メソッドで読み込んで、Processorに設定します。  
`target_field`と`target_value`を設定読み込みます。この時、デフォルト値としてそれぞれ`hello`と`world!`を指定するようにしておきます（`targetField`と`targetValue`というプロパティもHelloworldProcessorクラスに追加してあります。また、`plugin-security.policy`というファイルができていますが、今回は特に必要ないので、削除してあります）。

```java
    public static final class Factory implements Processor.Factory {

        @Override
        public HelloworldProcessor create(Map<String, Processor.Factory> factories, String tag, Map<String, Object> config) 
            throws Exception {
            String targetField = readStringProperty(TYPE, tag, config, "target_field", "hello");
            String targetValue = readStringProperty(TYPE, tag, config, "target_value", "world!");

            return new HelloworldProcessor(tag, targetField, targetValue);
        }
    }

```

次に、実際にDocumentに対して行われる前処理を実装します。  
これは、`execute`メソッドになります。引数の`ingestDocument`が前処理対象のドキュメントです。

```java
    @Override
    public void execute(IngestDocument ingestDocument) throws Exception {
        ingestDocument.setFieldValue(targetField, targetValue);
    }

```

その他に、Pluginクラスというのもあります。こちらは、`elasticsearch.yml`から設定を読み込む場合にこちらのクラスで設定します。今回のサンプルでは利用しません。  
さらにテストなどを書けば立派なプラグインの完成です。

## 実際にElasticsearchにinstallして動作確認

では、実際にElasticsearchに追加できるプラグインのZipを作ってみましょう。  
今回利用したプロジェクトテンプレートはGradleでビルドできるようにGradleのファイルも用意してくれています。  
ですので、以下のコマンドを実行すれば、テストの実行も行われ、zipファイルまで生成されます。

```auto
gradle clean check

```

ビルドが成功すると、`build/distributions`というディレクトリが作成され、  
`ingest-helloworld-0.0.1-SNAPSHOT.zip`が出来上がります。  
あとは、Elasticsearchにインストールです。

```auto
bin/elasticsearch-plugin install file:///path/to/ingest-helloworld/build/distribution/ingest-helloworld-0.0.1-SNAPSHOT.zip

```

インストールできたら、Elasticsearchを起動して、[Ingest APIのSimulate Pipeline API](https://www.elastic.co/guide/en/elasticsearch/reference/current/simulate-pipeline-api.html)で試しみましょう。

```auto
POST _ingest/pipeline/_simulate
{
  "pipeline": {
    "description": "sample",
    "processors": [
      {
        "helloworld" : {
        }
      }
    ]
  },
  "docs": [
    {"_source": {}}
  ]
}

```

すると`hello`というフィールドに`world!`という値が追加されているのが、レスポンスからわかります。

```json
{
  "docs": [
    {
      "doc": {
        "_index": "_index",
        "_type": "_type",
        "_id": "_id",
        "_source": {
          "hello": "world!"
        },
        "_ingest": {
          "timestamp": "2017-11-28T08:55:25.628Z"
        }
      }
    }
  ]
}

```

## まとめ

簡単ですが、Cookiecutterを利用したIngest Node pluginの作り方を見てきました。

実際に、この方法で、[ingest-csv plugin](https://github.com/johtani/elasticsearch-ingest-csv)を作成しています。テストの記述などについて詳しく知りたい方は参考にしていただければと思います。  
また、テンプレート自体は [https://github.com/spinscale/cookiecutter-elasticsearch-ingest-processor](https://github.com/spinscale/cookiecutter-elasticsearch-ingest-processor) にあります。

ぜひ、Ingest Nodeのプラグインで遊んでみてください！

---

<div class="post-metadata">

**Author:** ![warkolm](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/warkolm/32/39224_2.png) [@warkolm](https://discuss.elastic.co/u/warkolm)\
**Post date:** [August 23, 2018, 8:31am UTC](https://discuss.elastic.co/t/dec-2nd-2017-jp-elasticsearch-elasticsearch-ingest-plugin/109307/2 "2018-08-23T08:31:19Z")

</div>


