HadoopのMapperクラスについて。
(チュートリアルではMapperのクラス名はMapだが、java.util.Mapと紛らわしいな(苦笑))
|
|
Mapperは、入力をキーと値の組に分解(マッピング?)する。
(Reducerは、このキー毎に値を演算(たいていは集計)する)
Mapperの出力は、Combinerが指定されていればCombinerに渡されることがある。
Reducerが指定されていれば、Reducerに渡される。
Reducerが0個であれば、直接OutputFormatに渡される。
チュートリアルでは、値の出力は以下の様にコーディングされている。
public static class Map extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); context.write(word, one); } } }
Strutsやサーブレットプログラミングで“MTセーフ”に敏感になっている身としては、変数wordがフィールドに宣言されているのでマルチスレッドセーフになっていないのが気になる。
が、チュートリアルがこうなっているのだから、きっとMapperはマルチスレッドでは呼ばれないのだろう。
もうひとつ、context.write()にwordインスタンスをそのまま渡しているのも気になる。
内部でインスタンスを保持していたら、word.set()を呼ぶと保持している値が変わってしまうから。
context.write()の中身は、Reducerの個数で異なる。
Reducerが1個以上の場合はMapTask.
NewOutputCollectorのwrite()が呼ばれるが、シリアライズされる(wordのクラスであるTextのwrite()メソッドが呼ばれる)ので、インスタンスを直接保持するような事はしていないから大丈夫。
Reducerが0個の場合は直接OutputFormatに渡される。
TextOutputFormatではファイルストリームに出力しているので大丈夫。
TableOutputFormatではインスタンスのコピーを作って保持しているので大丈夫。
Mapper(Hadoop0.20.1)には以下のようなクラスがある。
自分でマッパーを作る際には、MapperかTableMapper辺りを親クラスに使うのが普通だと思う。
クラス名 | 入力型 | 出力型 | 説明 | ||
---|---|---|---|---|---|
KEYIN | VALIN | KEYOUT | VALOUT | ||
org.apache.hadoop.mapreduce. Mapper |
任意 | 任意 | 任意 | 任意 | 入力のキーと値をそのまま出力する。 →チュートリアル・サンプル |
org.apache.hadoop.mapreduce.lib.map. InverseMapper |
任意 | 任意 | VALIN | KEYIN | 入力のキーと値を入れ替えて出力する。 すなわち、出力キーは入力の値、出力値は入力のキーとなる。 |
org.apache.hadoop.mapreduce.lib.map. TokenCounterMapper |
Object (未使用) |
Text | Text | IntWritable | 入力値をトークンに分割して、トークンをキー、「1」を値として出力する。 つまりはチュートリアルWordCountのMapと全く同じ。 |
実行時にいくつのMapper(MapTask)が作られるのかは、InputFormat#getSplits()によって決まる。[2010-03-19]
(getSplits()は、処理しやすい単位に入力を分割して、処理単位(処理範囲・InputSplit)のリストを返す)
TextInputFormatなら、ファイルの個数やファイルサイズに応じて分割してくれる。
HBaseのTableInputFormatなら、テーブルのリージョン(領域)に応じて分割してくれる。