CentOS7.2 + Zeppelin0.7.0 + Spark2.0 + R3.3.1 + RMeCab(再)

前回の9月3日の記事と特に変わりはないはず。
ただし、今現在もZeppelin0.7.0はDeveloper版なのでちょっとは更新されているはず。

経緯としては、AccessLogを読み込むぜー!ってことで、Google先生にアドバイスを求めたら
Parserがお勧めと帰ってきたので取り込んでみた。

参考サイトのまま作り進めていくと、parserは標準からは分離されたということで、
interpreterにorg.scala-lang.modules:scala-parser-combinators_2.12:1.0.4と書いてから挙動がおかしい。

公式にもStatic initialization is deprecated and will be supported until 0.6.0.
ということで、なんとなくの原因はわかるが、解決方法が不明なことと、割と早く復旧しないとまずいので作り直し。
(幸か不幸か作り直しはもう慣れてる)

新バージョンで細かなバグが治っていることを祈りつつ・・・。

ーーーインストール

そして、前回の記事と全く操作変わらずにインストールできた。。
ネタがない!!w

あ、描画速度も体感できるレベルであがってる!
起動時間が長いとgoogleVisが読み込まれなくなる?バグっぽい挙動、
PINGログが出力されまくるのもなおってるぽい。

ついでにgoogleVisの見た目も少し変わってる。

セキュリティも権限がないとそもそも一覧にも出てこないのはナイス修正!
Jobからは見えるけど、Jobからの遷移もバグってるぽくHome画面にいくのでセーフ(?)

今、Import/Exportがちゃんと動いていないようなので、そこが直るのをまったほうがよさそう

Apache Zeppelinがバッチ処理に使える

たまたまバッチ処理をする必要が出てきたので、実装方法を考えたときにApache Zeppelinを使ってDBを更新すればいいじゃんという結論に。
Clone設定と同じように時間指定できるし、Re Runも簡単だし。

ってことを1つのプロジェクトで考えてた時に、
別プロジェクトでsh + python使ってバッチ処理作ってという依頼が。

Webサービスも古臭いなという印象を受けてたので、1ヶ月で見切りをつけた案件をしているチームからの依頼。
やっぱりpythonもすっごく古臭い。

それはともかく、Zeppelinをバッチで使うとなにが嬉しいかまとめてみる。
(大企業でZeppelinのようなものを使ってバッチ処理する世界は5年は先だと思うので)

  1. TeratermなどでのCUI操作が不要になる
  2. テストデータの挿入するなどのSQLを書いたりした場合、Zeppelin上で1元管理できる。実行したいときに再生ボタンを押すだけ!わざわざtxtに書いておかなくても大丈夫だし、それを探す&開く手間が不要。
  3. 接続先の変更が容易(interpreterの設定)
  4. Success/failが簡単に一覧で確認できる
  5. バージョン管理もできる(これちゃんと動いてる?)

メールを飛ばすなどする場合にはまだまだ作りこみが必要かもしれない。
ここは、自分が勉強不足なのか、そもそもバッチ用に作ってないからコンセプトとしてないのかもしれない。
ただ、当たり前にログ監視もできるので、Zeppelinにアクセスすればだいたいわかるとなると便利。

。。。メモリ2Gが最低要件でさえなければ。。。

AngularJs on Apache Zeppelin

よく読んだら公式情報でもわかるのかもしれないが、結構詰まったのであとで思い出せるように記事にする。
ここまではまったのは結構久しぶりかもしれない。

やりたかったことは、SELECTタグからひとつの値を選択。
選択した値を利用して、別のParagraphにて結果を出力していくというもの。
恐らく一般的な使い方になっていくのだろうが、あまりにもこの辺の情報が薄すぎる。

まずは最終的なソースから。

// scala
import org.apache.zeppelin.display.angular.paragraphscope._
import AngularElem._

// clear previously created angular object.
AngularElem.disassociate

// z.runでInterpreterが切り替わってしまうので保持
val interpreterContext = z.getInterpreterContext()

// db(dataframe から RowのListへ変換。SCALA<==>AngularはJSONでやり取りしているようなのでJSONも組み込みたい)
val location = sqlContext.sql("SELECT location FROM selectLocation")
var locationList = location.collect()

var selectList = org.apache.spark.sql.Row("")

// scala -> angular
z.angularBind("locationList", locationList)

///////////////// display /////////////////
<div>
<select ng-model="selectList" ng-options="list.values for list in {{locationList}}"></select>
<!-- <p>{{{{debug}}}}</p> -->
</div>.model("selectList",selectList).display

<div class="btn btn-primary">reference</div>.onClick(() => {
    val selectOne = AngularModel("selectList")()
    // AngularModel("debug", selectOne)
    z.put("selectOne", selectOne)
    z.run(24,interpreterContext)
}).display

<div class="btn btn-default">reference</div>.display
<div class="btn btn-info">reference</div>.display
<div class="btn btn-warning">reference</div>.display
<div class="btn btn-danger">reference</div>.display
<div class="btn btn-primary">reference</div>.display

上から順に説明すると、最初の数行はおまじない。
AngularElem.disassociateって本当に効果あるのだろうか?
これ以外にもParagraph実行するたびに遅くなっているのでまだまだ改善の余地ありということなのか、能動的にメモリ管理する必要があるのか。

interpreterに関しては、コメントにある通り、別のParagraphを実行してしまうとInterpreterContextが切り替わってしまう。
そうなると2回目の実行が出来ない。Errorlogを見てみると下記のように出ているはず。

ERROR [2016-10-03 01:57:21,622] ({pool-27-thread-2} AngularObject.java[run]:191) - Exception on watch
org.apache.zeppelin.interpreter.InterpreterException: Can not run current Paragraph

次に、SQLContextを利用して、Dataframeを取得。
そのままでは使い勝手が悪かったので、collectでListを取得。
最初はcollectAsListでjava.util.Listを取得していたが、こちらのほうが使い勝手悪かったのでArrayで取得。
どういう使い分けをするのが良いのだろうか。
取得した内容をangularBindでangularにBind。

.displayと書けばangularContextだと認識するようなことを公式に書いてあったので
//// display ////以下はAngularの話。

ng-modelには選択した値が入る(と思っている)

ng-optionsにはBindした値を設定。Arrayにはvaluesという値で入っているのでvalueにはvaluesを設定するように指定。
list.key as list.values for list in {{}}というような指定をすればkeyも設定できる。今回は無視。

pタグで囲まれているのはデバッグ用。BackendのAngularを使って変数を表示する場合、Escapeは2重に書くのかな。

で、<div>.model(・・・)で、AngularContextに値を設定。
公式情報見ているとScala to Angularのために書いているように見える。
実際にはClient to Serverってイメージかな?
公式情報にある、watchとrunも、どっちも+1しているせいで、runとwatchが同じ値を共有しているのかと思ったし。。。

最後にボタンの挙動。
AngularModel(str)()でAngularContextの内容を読み込み。
名前にListってあるのは最初はmultipleにしていたから。

AngularModel(str, obj)でAngularContextの内容をUpdate。

とりあえず、sparkContextにて使いたかったので、ZeppelinContext.putで保持。
その後、ZeppelinContext.runで実行。この際、コメントに書いてある通りinterpreterを指定しないとContextが変わる可能性があるので注意。
24はNotebook内にあるParagraphの順番。0始まり?

おまけで、cssを探った結果、buttonのclassに設定できるもの。
cssの情報はもうちょっとまとめてほしいし、JSFのようなshow case も欲しい。

ちなみにrunで実行した結果を、z.get(str)で取得するだけで終わってます。
z.angular(str)では思うように取得できなかった。

ZeppelinはContextが複数扱えて、その状況に合わせて最適な言語を選択できることは面白いけど
やっぱりそれを考えながら使うのは結構難しいっていうか、なんちゃってSEはついていけない気がする