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はついていけない気がする

Leave a Reply

Your email address will not be published. Required fields are marked *