Apache NiFiについて調べてみた


# この記事はなに？

Apache NiFiは，システム間のデータフローを管理するために作られたデータフローオーケストレーションツールです．

GUI（Web画面）によって，データフローの設定，制御，監視ができることが大きな特徴です．

Project page: https://nifi.apache.org/index.html
Github: https://github.com/apache/nifi

現在，NiFiを使うプロジェクトにアサインされ，調査をしており，調べたことを少しづつメモしておこうと思います．

# 環境

* Mac OS X 10.11.6
* Apache NiFi 1.4.0
* Java version 1.8.0_92


# NiFiのインストール

https://nifi.apache.org/docs/nifi-docs/html/getting-started.html#downloading-and-installing-nifi

上記instructionに従い，Homebrewを使ってインストールする．

```bash
$ brew install nifi
```

とりあえずステータスチェックをしてみる．

```bash
$ nifi status

NiFi home: /usr/local/Cellar/nifi/1.4.0/libexec

Bootstrap Config File: /usr/local/Cellar/nifi/1.4.0/libexec/conf/bootstrap.conf

2017-09-30 21:48:15,792 INFO [main] org.apache.nifi.bootstrap.Command Apache NiFi is not running
```

ここで`Java home`の値がおかしい場合は，先に環境変数等で適切に記述する必要がある．
`NiFi home`が，NiFiが用いるルートディレクトリ．

NiFiを起動してみる．

```bash
$ nifi start

Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home
NiFi home: /usr/local/Cellar/nifi/1.4.0/libexec

Bootstrap Config File: /usr/local/Cellar/nifi/1.4.0/libexec/conf/bootstrap.conf

$ nifi status

Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home
NiFi home: /usr/local/Cellar/nifi/1.4.0/libexec

Bootstrap Config File: /usr/local/Cellar/nifi/1.4.0/libexec/conf/bootstrap.conf

2017-09-30 21:59:25,018 INFO [main] org.apache.nifi.bootstrap.Command Apache NiFi is currently running, listening to Bootstrap on port 59714, PID=13895
```

デフォルトでは，localhostの8080番がNiFiのWeb UIに割り当てられるので，`http://localhost:8080/nifi`にブラウザからアクセスすることで，起動していることが確認できる．

![Kobito.ESORtv.png](https://qiita-image-store.s3.amazonaws.com/0/46811/2f4d10d1-cad7-2c1c-4375-5346051f4d2f.png "Kobito.ESORtv.png")

# 用語

最低限これぐらいは知っておくと良さそう．

* FlowFile
	* NiFiが取り扱うデータの単位．`Attributes`と`Content`からなる．
	* Attirbutes: 個々のFlowFileが持つ，key-valueベースのメタ情報．
	* Content: 扱うデータの本体．
* Processor
	* 「FlowFileにどんな処理を施すか」を表す．
	* データフローを記述したグラフ（DAG）におけるノードに相当する．
	* NiFiに組み込まれているものに加え，自分で実装したものを新たに組み込むことも可能．
* Relationship
	* 「Processorが行った処理に応じて，どのProcessorにどのFlowFileを届けるか」を表す．
	* データフローを記述したグラフにおけるエッジの属性に相当する．
	* 各Processorごとにあらかじめ定義されている．

# 触ってみる

とりあえず動かしてみたいだけなら，

Get Started: https://nifi.apache.org/docs/nifi-docs/html/getting-started.html
Hortonworks社による日本語チュートリアル: https://github.com/ijokarumawak/hdf-tutorials-ja/wiki/Ropes-of-Apache-NiFi%3A-Tutorial-1

あたりが参考になると思われる．

NiFiでデータフローを実現するための大きな流れとして，

1. 目的に応じたProcessorを探し/実装し，キャンバス上に追加する
2. Processor同士を結ぶ（各エッジについて，Relationshipを選択する）
3. Processorを設定する（多くのProcessorにはPropertyの設定が必要）
4. Processorを起動する

をする必要がある．

試しに，「各行がJSONになっているファイルを読み込んで，これを行単位で分割し，これをHTTPのPOSTパラメータとして送る」データフローを書いてみることとする．

## Processorの配置

今回使うProcessorは，

1. `ListFile`: ディレクトリを指定することで，そのディレクトリ中のファイルを検索する
2. `FetchFile`: 指定したファイルの内容を取得する
3. `SplitText`: ファイルを分割する
4. `InvokeHTTP`: HTTPアクセスを行う

の4つ．

![nifi1.png](https://qiita-image-store.s3.amazonaws.com/0/46811/216e648c-466a-6c6d-5641-96ea8ccb8450.png "nifi1.png")

上のボタンを押してキャンバス上にドラッグ&ドロップすると，

![Kobito.x6pAlz.png](https://qiita-image-store.s3.amazonaws.com/0/46811/f3e0dbc1-be25-023d-9f76-76e3b391bb80.png "Kobito.x6pAlz.png")

上のように，追加したいProcessorを選択する画面が現れる．

![Kobito.gS6hdQ.png](https://qiita-image-store.s3.amazonaws.com/0/46811/e5cd2e74-1c26-98fb-3bf8-48c8b5e95d90.png "Kobito.gS6hdQ.png")

ここで，`ListFile`を選んで，`ADD`を押すと，

![Kobito.bIIoU9.png](https://qiita-image-store.s3.amazonaws.com/0/46811/ff08716c-ac56-04f5-d406-32d342e39fcd.png "Kobito.bIIoU9.png")

Processorが配置される．

同様に，他のProcessorについても配置する．

![Kobito.4ACm7G.png](https://qiita-image-store.s3.amazonaws.com/0/46811/0b72e59a-3540-44e7-9a4a-d3ce864370e2.png "Kobito.4ACm7G.png")

## Processorを結ぶ

![Kobito.uY6sos.png](https://qiita-image-store.s3.amazonaws.com/0/46811/9bfd0ed2-cee7-dd74-2deb-e825414530a1.png "Kobito.uY6sos.png")

のような矢印が出ている状態でProcessor同士をドラッグ&ドロップすると，Processor同士を線で結ぶことができる．

![Kobito.Uuypxp.png](https://qiita-image-store.s3.amazonaws.com/0/46811/67ba678b-6b4d-f48c-a985-cfa64d8f342e.png "Kobito.Uuypxp.png")

`For Relationship`の欄には，どのようなRelationshipでProcessorを結ぶかを指定する．
ここでは，`success`を指定する．

![Kobito.L1ONFy.png](https://qiita-image-store.s3.amazonaws.com/0/46811/ff081995-6210-2fed-2ecc-8b65784597fc.png "Kobito.L1ONFy.png")

`success`のRelationshipで結べたことが確認できる．

同様に，他のProcessorも結ぶ．

![Kobito.uiAgS2.png](https://qiita-image-store.s3.amazonaws.com/0/46811/2c97317b-1826-2a24-e950-6915d7ec40fa.png "Kobito.uiAgS2.png")

## Processorを設定する

このままでは，どのProcessorにも設定値がないので動作しない．

Processorを右クリックし，`Configure`をクリックすることで，Processorの設定を行うことができる．

![Kobito.eGVUEF.png](https://qiita-image-store.s3.amazonaws.com/0/46811/2bf550ac-aa0c-cb5d-e007-b9bdd5aebfa5.png "Kobito.eGVUEF.png")

ここでは，`PROPERTIES`タブを選択し，`Input Directory`に，ファイルを検索したいディレクトリのパスを入力する．

![Kobito.469RXD.png](https://qiita-image-store.s3.amazonaws.com/0/46811/2a095ec6-950d-b88b-a291-e741a2788a6d.png "Kobito.469RXD.png")

![Kobito.2dsZwj.png](https://qiita-image-store.s3.amazonaws.com/0/46811/8ee2b928-e304-74ee-f7f9-eff332144f2c.png "Kobito.2dsZwj.png")

先ほどは，`ListFile`のProcessorに黄色い「注意」のマークがついていたが，これが，赤い「停止」のマークに変わっていることがわかる．
これで，このProcessorについては，起動準備ができたことになる．

「注意」のマークにマウスカーソルを合わせると，何が起動条件として満たされていないのかが表示されるので，参考にするとよい．

![Kobito.rGVoj8.png](https://qiita-image-store.s3.amazonaws.com/0/46811/0d46cbc6-6738-2858-bdac-12be60a5b06c.png "Kobito.rGVoj8.png")

基本的に，すべての入力必須なPropertyは入力されていなければならず，また，Relationshipについては，他のProcessorと結んであるか，または「どことも結ばない」ことを明示する必要が有ることに注意．
「どことも結ばない」ことを明示する場合は，`SETTINGS`タブの`Automatically Terminate Relationship`から選択する．

![Kobito.lFO8Ai.png](https://qiita-image-store.s3.amazonaws.com/0/46811/4819ec5e-9ca3-987d-603d-542dc1f8a095.png "Kobito.lFO8Ai.png")

同様に，他のProcessorについても設定を行う．

![Kobito.GOXGWd.png](https://qiita-image-store.s3.amazonaws.com/0/46811/8d378b0d-4fc1-53be-0a44-14d4efff6b85.png "Kobito.GOXGWd.png")

（今回，異常系については省略しているが，実際のデータフローでは，失敗時の処理も記述すべきである．）

## Processorを起動する

![Kobito.Bqzk1Y.png](https://qiita-image-store.s3.amazonaws.com/0/46811/47c51958-b0cf-09db-9f06-60c9148579de.png "Kobito.Bqzk1Y.png")

上のように，起動したいProcessorを選択した上で，「再生」ボタンを押すことで，Processorを起動できる．

![Kobito.T4fwaa.png](https://qiita-image-store.s3.amazonaws.com/0/46811/8f3805a6-39bd-8183-adfd-0f4d2e12b027.png "Kobito.T4fwaa.png")

実際のデータの流れを追いたい時は，Data Provenanceを用いるとよい．

例えば，`SplitText`の処理を追いたい場合は，

![Kobito.P4tgWR.png](https://qiita-image-store.s3.amazonaws.com/0/46811/b2ef8814-f6e5-45ac-6d5d-bcafe077b418.png "Kobito.P4tgWR.png")

のように，`SplitText`のメニューから`Data Provenance`を選択する．

![Kobito.Un9hww.png](https://qiita-image-store.s3.amazonaws.com/0/46811/097a4bf0-2419-d8f3-a1ef-c9cb68fab831.png "Kobito.Un9hww.png")

上の画面で，`SplitText`を通過したデータの一覧を見ることができる．

実際のデータの内容を確認したい時は，一番左の「i」ボタンを押し，`CONTENT`タブから，`VIEW`ボタンを押す．
Processorへの入力，出力両方のデータが見られる．

![Kobito.IijGnU.png](https://qiita-image-store.s3.amazonaws.com/0/46811/9c491439-e166-8fa4-128e-a31c2c5aaedf.png "Kobito.IijGnU.png")

ちなみに，`InvokeHTTP`の方の入力データを見てみると，ちゃんと行単位でデータがsplitされていることが確認できる．

![Kobito.PPbL4x.png](https://qiita-image-store.s3.amazonaws.com/0/46811/94b50c3f-9100-e60c-4f95-0f8bc8cb9cdf.png "Kobito.PPbL4x.png")

![Kobito.o9jNOk.png](https://qiita-image-store.s3.amazonaws.com/0/46811/58f1bbe8-b7fb-988c-dd73-e94098dbe540.png "Kobito.o9jNOk.png")