Asakusa FrameworkをScalaで記述するライブラリー「AfwHS」α版。
|
AfwHSは、Scalaで記述したコードをAsakusaFWの(Java)DSLに変換して実行できるようにするライブラリー。
AfwHSはコードネーム「AsakusaFramework Hishidama Scala」の略かなぁ(苦笑)
「Hishidama」なんて恥ずかしい単語が入っている理由は、AsakusaFWでScalaと言えばasami224さんの「Asakusa
Scala DSL」の事を指すので、違いを出す必要があるから…。
「AfwHS」を何て発音すればいいか分からないから(爆)、「AHS」でいいかも。
DMDLで作ったJavaのモデルクラスを元に、AsakusaFWの演算子(アノテーション)を模したScalaの関数(これがAfwHSで用意されているもの)を使って処理を記述する。
それを元にAsakusaFWのOperator・JobFlowを生成する。
とりあえず作ってみたって感じなので、α版。
AfwHSでWordCountを書くと、こんな感じ。
import scala.collection.JavaConverters._ import jp.hishidama.afwhs._ import sample.wordcount.modelgen.dmdl.model.LineModel import sample.wordcount.modelgen.dmdl.model.LineModelWrapper import sample.wordcount.modelgen.dmdl.model.LineModelImplicit._ import sample.wordcount.modelgen.dmdl.model.WordCountModel import sample.wordcount.modelgen.dmdl.model.WordCountModelWrapper import sample.wordcount.modelgen.dmdl.model.WordCountModelImplicit._
object WordCount {
def run(in: Source[LineModel]) = { val split = in.cogroup("split", "", Result[WordCountModel]("out")) { (s, r) => s.asScala.foreach { _.getTextAsString().split("[ \t]+").foreach { word => r.add(WordCountModelWrapper(word, 1)) } } } val count = split.cogroup("sum", "word", Result[WordCountModel]("out")) { (s, r) => val word = s.get(0).getWordAsString() val count = s.asScala.map(_.getCount).sum r.add(WordCountModelWrapper(word, count)) } count //戻り値 }
青い字はDMDLによって生成されたモデルクラスやそのメソッドそのもの。
オレンジ色のはモデルのScala用ラッパークラス。これもモデルドライバーの機能で生成される。
Source/ResultやcogoupはAsakusaFWのクラス(DSL)を模したもので、AfwHSで用意しているクラスやメソッド。
s0はデータモデルのjava.util.List
で、CoGroupの引数と全く同じ。
r0も同じくCoGroupで戻り値を返すResultそのもの。
その他は普通のScalaのメソッド・関数。
このrunメソッドを呼び出す方法が2種類ある。
def main(args: Array[String]) { if (!args.exists(_ == "generate")) { // 普通にデータを渡して実行する val slist = List("Hello World", "Hello Asakusa", "Hello Hadoop") val mlist = slist.map { text => LineModelWrapper(text).asJava } val r = run(Source(mlist)) println(r) } else { // Asakusa DSLを生成する val gen = new Generator("C:/workspace", "afwhs-wordcount", "sample.wordcount", "WordCount") val r = run(gen.newSource()) gen.out(r) gen.prepareGenerate() gen.generateOperator() gen.generateImporter() gen.generateExporter() gen.generateFlow() gen.generateFlowTest() } } }
とりあえず、実行時の引数に「generate」という文字列が入っているかどうかで処理を分岐している。
generate 以外 |
Sourceに入力データ(データモデルのリスト)を渡すと、そのデータを使って実際に処理を行って結果のデータ(データモデルのリスト)を返す。 ((AsakusaFWのデータモデルを使っているという以外は)AsakusaFWやHadoopとは無関係に単なるScalaのプログラムとして実行する)
|
generate | SourceにGeneratorから作ったオブジェクトを渡すと、Asakusa DSL生成用の情報収集を行う。 generateXxx()でAsakusa DSLの生成を行う。 |
α0.001 | とりあえずイメージを作ってみた。 | [/2011-08-23] |
α0.002 | ソースの自動生成を作ってみた。実行は途中までしか出来ない。 | [/2011-08-22] |
α0.003 | α0.002の実行が途中までしか出来ない問題点をどうするか考えた。 | [2011-08-23] |
α0.004 | DMDLを使い、ラッパークラスを生成することにした。 | [2011-08-23] |
とりあえず最小限は動かせる状態になった。 | [2011-08-28] | |
JobFlowのテストクラスの生成処理を追加。 | [2011-08-31] | |
prepareGenerate()を新設。fold演算子を追加。 | [2011-09-04] | |
afwhs.javaパッケージをafwhs.forjavaに変更。 | [2011-09-16] |