2011年12月01日

ScalaでMapReduceの面倒な記述を省略しようとしたメモ

ScalaでMapReduceする際の記述は、以下のサイトがとても参考になった。

ScalaでHadoopのWordCount
http://www.ne.jp/asahi/hishidama/home/tech/scala/sample/hadoop.html

上記のサイトでも登場するけど、ScalaHadoopというMapReduce時の記述を楽にしてくれるライブラリがいるらしい。面倒な記述が自動化されている上にChainで処理が書けてしまうなかなか面白いライブラリ。

個人的にはそこまでやらずに、面倒なところを共通化してくれたらあとは基本機能がむき出しになっている方が好きなので、ScalaHadoopを参考に自分に必要な処理だけ共通化する形を考えてみた。



とりあえずこの辺が省略できれば良いよね。

・Job関連
job.setJarByClass
job.setMapperClass
job.setReducerClass
job.setCombinerClass
job.setOutputKeyClass
job.setOutputValueClass

・Mapper/Reducer関連
Contextのtype指定
Reducerの引数をjava.lang.IterableからScalaの型へ変換
Text⇔String、IntWritable⇔Intなどの型変換

そのためには出力する型を取得できるMapperとReducerを定義して、両者のインスタンスを渡せば自動でsetJarByClass、setMapperClass、setReducerClass、setOutputKeyClass、setOutputValueClassが設定されるようにすれば良さそう。

上記で定義するMapperとReducerには、Contextのtype指定やText⇔Stringなどの暗黙の型変換に関する記述(SHadoopから拝借)もしておく。

他にも指定したい項目がある場合は、Jobに対して直接記述できるようにする。

という感じでごそごそと書いていったらこうなった
https://github.com/mwsoft/sample/tree/master/shadoop/src/main/scala/jp/mwsoft/sample/shadoop

MapperとReducerを拡張したクラスが、SMapperとSReducer。

あとはToolを拡張したSToolというクラスを作成。これを継承して中でMapperとReducerを指定し、createJobメソッドを呼び出すといろいろな値が自動で設定されるようにする。

結果、単純なWordCountの処理はこんな風に書けるようになった。

import jp.mwsoft.sample.shadoop.{ STool, SMapper, SReducer }
import org.apache.hadoop.io.{ LongWritable, Text }

object WordCountSample extends STool {

// Toolのrunメソッド
override def run( args: Array[String] ): Int = {
// Job名、入力パス、出力パスを指定すると、自動でいろいろセットされたJobが返る
val job = getJob( "wordCount", "data/in", "data/out" )
// あとはrunするだけ
run( job )
}

// Mapperをここに定義
override val mapper = new SMapper[LongWritable, Text, Text, LongWritable]() {
override def map( key: LongWritable, value: Text, context: Context ) {
value.split( " " ) foreach ( x => context.write( x, 1L ) )
}
}

// Reducerをここに定義(省略可)
override val reducer = new SReducer[Text, LongWritable, Text, LongWritable]() {
override def reduce( key: Text, values: Iterator[LongWritable], context: Context ) {
val sum = values reduceLeft ( _ + _ )
context.write( key, sum.toLong )
}
}
}


SToolでmainメソッドも実装してあるので、このまま実行できる。一応、CombinerもReducerと同じように指定できる。

まだまだ省略できるところはあるけど(クラスを省略してmapメソッドやreduceメソッドだけ記述するとか)、これ以上やると生のところと距離が生まれてしまうのでこの辺で良しとする。

個人的にこの手の処理は書き捨てることが多いのでMapperとReducerがセットで(しかも匿名で)中にまとめて入ってるととても落ち着く。あまり好まれる書き方ではないと思うけど。