だいたいゼロから始めるApache Zeppelin(機能紹介編)

## シリーズのリンク

1. 機能紹介編
1. [インストール・起動・停止編](https://qiita.com/muterion111/items/4caf9c227fac12c1560c "だいたいゼロから始めるApache Zeppelin(インストール・起動・停止編)")
1. [設定編](https://qiita.com/muterion111/items/c6547b444bbbac6c4737 "だいたいゼロから始めるApache Zeppelin(設定編)")
1. [Sparkインタープリタ編](https://qiita.com/muterion111/items/557197d58a5eaee2af86 "だいたいゼロから始めるApache Zeppelin(Sparkインタープリタ編)")
1. [その他インタープリタ編](http://qiita.com "だいたいゼロから始めるApache Zeppelin(その他インタープリタ編用)")(予定)

## 要約

- Apache ZeppelinはSparkを中心としつつ  
Redshift、BigQueryなどの他データソースにも対応できるノートブック。
- Apache Zeppelinはフォーム入力やバージョン管理、  
ノートのスケジュール実行ができるなど高機能なノートブック。

## このシリーズの対象読者

- データ分析プラットフォームに興味はあるが詳しくは知らない。
- 設定などSparkに関する基本的な事項は把握している。
- Javaで一般的な依存性管理方法は把握している。

## 注意(必ずお読みください)

- 以下は免責事項です。
  - 本シリーズに掲載された内容は投稿者の個人的見解であり、  
  所属する企業・部門の公式見解ではありません。 
  - 本シリーズに掲載された内容について  
  可能な限り正確を期すようにしておりますが、  
  掲載された内容の正確性、信頼性、完全性を  
  保証するものではございません。 
  - 本シリーズに掲載された内容によって生じた  
  あらゆる損害等に関して投稿者ならびに所属する企業・部門は  
  一切の責任を負いません。
- 将来的に追加、変更、廃止される機能も当然ございますので  
Apache Zeppelinを使用する際は[公式ページ](http://zeppelin.apache.org/)にて確認をお願いいたします。
- このシリーズではSparkやScalaといった  
Apache Zeppelin以外の事項に関しては解説いたしません。  
それぞれについて解説しているサイトにて確認をお願いいたします。

## このシリーズでの環境

- OS  
macOS
- メモリ  
16GB
- Java  
OpenJDK 64-Bit Server VM, Java 1.8.0_232
- Scala  
2.13.1
- Apache Zeppelin  
0.8.2
- Apache Spark  
2.4.4

## シリーズの背景

[Apache Zeppelin](http://zeppelin.apache.org/)については以前から興味があって
個人的にいろいろ試したりしていました。
ただ今の職場では主に省力化の観点からクラウド環境のみ使用する方針なので、
Apache Zeppelinを実際の仕事に用いるにはフルマネージドのサービスとして
提供されてなければ無理かなと思っております
([AWS EMR](https://docs.aws.amazon.com/ja_jp/emr/latest/ReleaseGuide/emr-zeppelin.html)や[Cloud Dataproc](https://cloud.google.com/dataproc/docs/concepts/components/zeppelin?hl=ja)といったある程度マネージするものはあります)。
Apache Zeppelinを活用する人が増えたら
フルマネージドのサービスが提供されるかも？
みたいな淡い期待を持ってこのシリーズを初めてみました。
このシリーズを読んでいただいてApache Zeppelinについて
少しでも興味を持っていただけたら幸いです。

## Apache Zeppelinとは

Sparkから取得したデータを表やグラフとして表示することを主用途としつつ、
RedshiftやBigQueryなどの他データソースからのデータも同様に表示したり、
Scala、Python、R、Shellコマンドを実行できたりなどと **いろいろできる
Scalaで実装された高機能なノートブック** です。
なおライセンスは[Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)です。

## ノートブックとは

Apache Zeppelinはノートブックなのですが、
ノートブックとは何かというと以下のものになります。

```text
文芸的プログラムを記述する環境となる仮想的なノート
```

[参照](https://en.wikipedia.org/wiki/Notebook_interface)  

では文芸的プログラムとは何かというと
簡単に言えば以下のものになります。

```text
ブラウザ等でプログラムコードとコメントを
入力してそれらを別々に処理した結果を出力するもの
```

[参照](https://ja.wikipedia.org/wiki/文芸的プログラミング)

このためノートブックのユーザにプログラムコードの出力結果が何かを
コメントによってわかりやすく説明することができます。
プログラムコードとコメントは主にエンジニアが書くものとなりますが
 **どんなに複雑なプログラムコードであっても付随するコメントにより
非エンジニアがその出力結果を比較的容易に理解・利用できる** ことが
ノートブックを使用する利点だと個人的に考えております。

## Apache Zeppelinの機能(一部抜粋) 

1. [インタープリタ](http://zeppelin.apache.org/docs/0.8.2/#available-interpreters)  
    Apache ZeppelinはSpark、Spark SQLやRedshiftなどの
    JDBCを通してアクセスできるものなどの各種データソースや、
    Markdownなどのコメントを出力するものなど
    多種多様な機能を実行できるノートブックとなっております。
    この`多種多様な機能`それぞれをできるようにするためのプラグインを
    総称して **インタープリタ** と呼びます。
    後述するコードセクションの先頭行に`%インタープリタ名`と指定することで
    そのインタープリタに対応する機能が実行可能になります。
    デフォルトで組み込まれているインタープリタは以下のものになります。

    |機能|インタープリタ名|  
    |:-:|:-:|  
    |Alluxio|%alluxio|  
    |AngularJS|%angular|  
    |BigQuery|%bigquery|  
    |Apache Cassandra|%cassandra|  
    |Elasticsearch|%elasticsearch|  
    |HDFS|%file|  
    |Apache Flink|%flink|  
    |Groovy|%groovy|  
    |Apache HBase|%hbase|  
    |Apache Ignite|%ignite|  
    |Redshift/MySQLなど|%jdbc|  
    |Apache Kylin|%kylin|  
    |Apache Lens|%lens|  
    |Apache Livy|%livy|  
    |Markdown|%md|  
    |Neo4j|%neo4j|  
    |Apache Pig|%pig|  
    |Python(2系か3系かは設定による)|%python|  
    |SAP BusinessObjects|%sap|  
    |Shellコマンド|%sh|  
    |Apache Spark|%spark|  
    |PySpark|%pyspark|  
    |SparkR|%spark.r|  
    |Spark SQL|%sql|  

    またインタープリタを自作する機能もあります。

1. [セキュリティ](http://zeppelin.apache.org/docs/0.8.2/#setup)  
    Apache Zeppelinでは下記に関するセキュリティに関する設定ができます。
    - NGINXを用いたベーシック認証
    - Shiroによるログイン認証
    - Shiroによる各種アクセス権限認可
    - データソースへのログイン認証
    - HTTPレスポンスヘッダによるセキュリティ制御

    このうち`Shiroによるログイン認証`と`Shiroによる各種アクセス権限認可`に関して
    追加の説明をします。
    この２つで使われる[Apache Shiro](http://shiro.apache.org/)はJava製の
    認証・認可・暗号化・セッション管理フレームワークです。
    ログイン認証する際には以下のコマンドでテンプレートをコピーした後、
    (コマンド等はApache Zeppelin使用環境に応じて適切に変更してください)

    ```sh
    cp ./conf/shiro.ini.template ./conf/shiro.ini
    ``` 

    この`shiro.ini`内の以下の`users`セクションの箇所で
    ユーザ名とパスワード、ロールの設定が行えます。

    ```text
    [users]
    # List of users with their password allowed to access Zeppelin.
    # To use a different strategy (LDAP / Database / ...) check the shiro doc at http://shiro.apache.org/configuration.html#Configuration-INISections
    # To enable admin user, uncomment the following line and set an appropriate password.
    #admin = password1, admin
    user1 = password2, role1, role2
    user2 = password3, role3
    user3 = password4, role2
    ``` 

    設定後にApache Zeppelinを再起動すると下記のログイン画面にて
    上記で設定したユーザ名等でログインできるようになります。
    ![ログインの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/d06e9b52-caad-c6d8-0909-63fec9cc6564.png)  

    各種アクセス権限認可は前提として **Shiroによるログイン認証の
    設定をすることが必要** となります。
    以下の画面にあるようにノートの右上にある鍵のアイコンをクリックすると
    表示されるフォームで`shiro.ini`で設定した各ユーザに対して
    ノートの所有者(Owners)ならびにノートの各パラグラフに対する
    書き込み権限(Writers)、実行権限(Runners)、読み込み権限(Readers)を
    設定できます。
    ![各種アクセス権限認可の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/91da9997-6093-7aef-abdd-1870d0748f98.png)  

    例えばあるパラグラフに対してそれに書き込む権限がないユーザが
    書き込もうとすると下記の画面のようなエラーダイアログが表示されます。
    ![権限エラーの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/f218cdc6-1d6a-9717-05e1-39836907c6bd.png)  

1. [リッチなUI](http://zeppelin.apache.org/docs/0.8.2/quickstart/explore_ui.html)  
    Apache Zeppelinでは実行単位である **パラグラフ** というものを
    **ノート** というものでグルーピングした状態で管理しております。
    さらに **パラグラフ** ではコードを記述する **コードセクション** と
    それコードの実行結果を表示する **リザルトセクション** の
    ２つに区分けされます。
    このパラグラフは高さの自由な調節と幅の段階的な調節ができます
    (ノート内での位置はパラグラフ間の表示順序を変えられるだけです)。
    以下は機能例です(これはApache Zeppelinのチュートリアルにあったのを
    見やすくするために簡易化したものです)。
    上部にあるパラグラフに対して下部のパラグラフの幅を半分にしてます。
    ![ノートのUIの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/f7d2783f-b656-ad78-b50e-9c9e10cdb5a4.png)  

1. [Dynamic Form](http://zeppelin.apache.org/docs/0.8.2/usage/dynamic_form/intro.html)  
    インタープリタが  **JDBC** や **Spark SQL** のようにSQLを用いるもの、
    **Markdown** や **Shellコマンド** のように文字列を用いるものには
    コードセクションに`${フォーム名}`というような記述をして実行すると
    同じパラグラフのリザルトセクションにフォームが出力され、
    コードセクション内のその記述がフォームへの入力値で置き換えられます。
    またインタープリタが　**Spark** または **PySpark** の場合には
    上記の代わりに`z.textbox(・・・)`のようなメソッドを呼び出すと
    同様にリザルトセクションにフォームが出力され、
    フォームへの入力値がこのメソッドの戻り値として取得できます。
    この機能は **Dynamic Form** というものでコードセクションに
    リテラルを書き込む必要性がなくなることで、
    例えばコードの処理に対するパラメタとして指定する値を変更する際に
    コードに不具合が混入する可能性がなくなります。
    Dynamic Formにはいくつか種類があります。
    以下はコードセクションにSQL、文字列を記述する
    インタープリタの場合です。

    ```text
    # テキストボックス
    ${フォーム名}
    ${フォーム名=デフォルト値}
     
    # セレクトボックス
    ${フォーム名=デフォルト値,オプション値1|オプション値2|・・・}
    ${フォーム名=デフォルト値,オプション値1(表示名1)|オプション値2(表示名2)|・・・}
    
    # チェックボックス
    ${checkbox:フォーム名=デフォルト値1|デフォルト値2|・・・,オプション値1|オプション値2|・・・}
    ${checkbox(区切り文字列):フォーム名=デフォルト値1|デフォルト値2|・・・,オプション値1|オプション値2|・・・}
    ```

    以下は　**Spark** または **PySpark** の場合です。

    ```text
    # テキストボックス(Spark/PySpark)
    z.textbox("フォーム名")
    z.textbox("フォーム名","入力値がない場合のデフォルト値")
    
    # セレクトボックス(Spark)
    z.select("フォーム名",Seq(("オプション値1","表示名1"),("オプション値2","表示名2"),・・・))
    
    # セレクトボックス(PySpark)
    z.select("フォーム名",[("オプション値1","表示名1"),("オプション値2","表示名2"),・・・])
    
    # チェックボックス(Spark)
    z.checkbox("フォーム名",Seq(("オプション値1","表示名1"),("オプション値2","表示名2"),・・・))
    .mkString("区切り文字列")
    
    # チェックボックス(PySpark)
    "区切り文字列".join(z.checkbox("フォーム名",[("オプション値1","表示名1"),("オプション値2","表示名2"),・・・]))
    ```

    なおデフォルトではこれらのフォームの入力値を変更すると
    即座にその入力値を元にしてコードセクションの処理内容が実行されます。
    即座に実行されないようにするためにはパラグラフの右上にある
    歯車のアイコンをクリックすると表示される`Run on selection change`の
    チェックボックスのチェックを外す必要があります。
    以下はDynamic Formの実装例です。
    ![Dynamic Formの実装例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/cd4b9a2e-8eee-f429-b243-68f86650085d.png)

1. [AngularJS](a)  
    Apache ZeppelinでAngularJSを使用して見栄えがするノートを作成できます。
    Dynamic Formと同様にSparkのインタープリタのコードセクションで
    特定メソッド呼び出しで用いる方法もありますが、
    その場合には大抵Dynamic Formで事足りるため、
    実用性を考慮するとAngularJSのインタープリタのコードセクションで
    各パラグラフにフォームの入力値を反映させるUIを
    作成していくことになると思います。
    AngularJSのインタープリタで使用できるAPIは以下のとおりです。
    なお下記の`パラグラフID`は各パラグラフの右上の歯車のアイコンを
    クリックした際に出力されるメニューの一番上に
    表示される文字列のことを指します。

    ```text
    # Angularオブジェクトに値を設定する
    z.angularbind(Angularオブジェクト名,初期値,パラグラフID) 
    
    # Angularオブジェクトを解放する
    z.angularUnbind(Angularオブジェクト名,パラグラフID) 
    
    # 別のパラグラフを実行する
    z.runParagraph(パラグラフID) 
   ```

    他のパラグラフでは各インタープリタにて下記方法でその値を取得できます。

    ```text
    # AngularJS
    {{Angularオブジェクト名}} 
    
    # Spark
    z.angular("Angularオブジェクト名") 
    ``` 
    
    以下の画面のようにAngularJSのインタープリタのパラグラフを実行すると
    そのパラグラフのリザルトセクションのフォームへの入力値が
    他の２つのパラグラフにも反映されます。
    ![AngularJSの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/54abaf94-cb99-6ac5-818f-39dfc814bc3c.png)  

1. [バージョン管理](http://zeppelin.apache.org/docs/0.8.2/usage/other_features/notebook_actions.html)  
    パラグラフを追加またはパラグラフのコードセクションを変更後に
    下記画面のようにメモのアイコンをクリックすることでその修正を
    組み込みのgitのリポジトリにコミットできます。
    ![コミットの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/1d35bcd7-ef42-615a-13bb-93b8bd06df7e.png)  

    以前のコミット時の状態を表示(修正・実行はできません)する場合は
    下記画面のようにコミットメッセージの右隣のアイコンをクリックすることで
    選択したコミット時の状態の表示できます。
    ![コミット時の状態表示の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/0f62fdbf-f864-0607-f1d6-eaf918bdfa46.png)  

    上記で別のコミットを選択した状態で下記画面のように
    右矢印のアイコンをクリックすることで選択したコミット時の状態に
    リセットするかのダイアログが表示され、
    OKボタンをクリックするとリセットできます(リセット前のコミットは
    失われませんが、コミットしていない修正は失われます)。
    ![リセットの例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/4a095bf6-22e2-856a-c470-a4f3bfcc9fd0.png)  

    また下記画面のように左右を示している矢印のアイコンをクリックすることで
    コミット間の差分の表示もできます。
    ![コミット間差分表示の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/69b351a1-502d-00b7-1ee9-e360d5f702cd.png)    
    
1. [スケジュール実行](http://zeppelin.apache.org/docs/0.8.2/usage/other_features/cron_scheduler.html)  
    この機能を使用するためには以下のコマンドでテンプレートをコピーした後、
    (コマンド等はApache Zeppelin使用環境に応じて適切に変更してください)

    ```sh
    cp ./conf/zeppelin-site.xml.template ./conf/zeppelin-site.xml
    ``` 
    
    この`zeppelin-site.xml`にて
    `zeppelin.notebook.cron.enable`プロパティのコメントアウトを外した後で
    値を`true`した後にApache Zeppelinを再起動をすることが必要となります。

    ```text
    <property>
      <name>zeppelin.notebook.git.remote.origin</name>
      <value>origin</value>
      <description>Git repository remote</description>
    </property>
    -->
    <property>
      <name>zeppelin.notebook.cron.enable</name>
      <value>true</value>
      <description>Notebook enable cron scheduler feature</description>
    </property>
    <!--
    <property>
      <name>zeppelin.notebook.cron.folders</name>
      <value></value>
      <description>Notebook cron folders</description>
    </property>
    -->
    ``` 

    上記手順を踏むと各ノートに下記画面のような時計のアイコンが表示され、
    このアイコンをクリックすることでノートに属する全パラグラフに対して
    実行スケジュールを設定できるようになります(パラグラフ単位の
    実行スケジュールは設定できません)。
    ![スケジュール設定前の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/09ed517a-229e-8776-5632-d01ec33b4295.png)  

    実行スケジュールの設定は`1m`などのリンクをクリックするか、
    手動でcron形式の文字列をテキストボックスに入力することでできます。
    ![スケジュール設定後の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556213/83a92029-37ef-dd40-5330-27d6bc8d33cb.png)    
    
## つづき
次回は[インストール・起動・停止編](https://qiita.com/muterion111/items/4caf9c227fac12c1560c "だいたいゼロから始めるApache Zeppelin(インストール・起動・停止編")です。