3.MapReduceフレームワークの構造
ここまでの知識を駆使して、Hadoop MapReduceの構造を見直しましょう。
Hadoop MapReduceは、分散集計などを行うフレームワークです。フレームワークですから、次のような特徴があります。
- 全体の動作が決まっている
- アプリケーションとして一部のロジックを埋め込む
図2を使って、MapReduceの全体を確認していきます。色のついている部分は、MapReduceプログラムを書くプログラマが用意するファイルやプログラムです。

入力ファイルからMap処理
フレームワークがファイルを読み込み、Map処理へデータ(キーとバリュー)を渡すのはInputFormatの役割です。入力ファイル(群)は、入力フォーマットによって分解され、「レコード」という単位でMapperの「map」メソッドに渡されます。先ほど触れたように、デフォルトではTextInputFormatクラスが働くので、<LongWritable, Text>が使われます(図中の赤い<Key, Value>)。後ほどコードでも確認しますが、Mapクラスのベースクラス「Mapper」はジェネリック型なので、その型定義に<LongWritable, Text>を使うことになります。この場合、例えば、100行あるファイルが3つあると、300行に分解されるため、MyMapperクラスのmapメソッドはクラスタ内合計で300回呼び出されます。
入力レコードは「Split(スプリット=断片)」に分けられ、mapへ渡されます。このスプリットの単位で、TaskTrackerへ分散され、平行処理されるわけです。
シャッフル
シャッフルはMapの出力をソートし、Reduceへ渡すプロセスです。Hadoopの提供するプログラムが行います。シャッフルの入力はMapクラスの出力です。シャッフルの出力は、Reduceの入力です。シャッフル処理は型変換を行わないので、Mapの出力は、Reduceの入力と一致している必要があります。図中緑の<Key, Value>がこれに当たります。
Mapからの同一キーに対する出力件数が多い場合「Cobiner(コンバイナー)」というクラスが働くこともあります。それぞれのMap出力が、いったんCombinerで処理された後に、シャッフル処理が実施されます。シャッフルのレコード数を減らすのが目的で、独自に書いてもよいですし、プログラムの集計方法が一致する(数を数えるなど)ならば、Reducerと同じものを使うこともできます。単語を数えるサンプルは、ReducerがConbinerとして設定されているものをよく見かけます。今回提供するサンプルも、論理的に同じでよいので、ReducerをCombinerとして登録しています。Combinerは、それぞれのMapに対して独立に実行されるので、複数のMapからの出力が、まとめて一つのCombinerに渡るわけではありません。また、1つのMapの処理が完全に終了する前に実行されることもあります。Combinerが実行されるタイミングがユーザー側で制御するができませんので、使う場合は注意が必要です。
Reduce処理から出力ファイル
シャッフルでソートされた、Mapperからの出力レコードは、同じキーでグルーピングされてReducerのreduceメソッドに渡されます。例えば、単語を数えるプログラムであれば、単語の種類の数だけ、reduceメソッドが呼ばれます。
Map出力の型とReduce処理の入力は同じでなければなりませんが、出力はプログラマがある程度自由に決められます。出力はOutputFormatに渡されます。図中、青色の<Key, Value>です。
ここまでの説明のように、キーとバリューの組み合わせは、MapReduceジョブの中で3組が存在し、プログラム中では、表X.のように整合性がとれている必要があります。
| ファイルからの入力 | InputFormat出力 | Map入力定義 | ||
| シャッフル時 | Map出力 | Reduce入力定義 | ||
| ファイルへの出力 | Reduce出力 | OutpuFormat出力 |
では、いよいよソースコードを眺めながら、1行ずつ解釈していきましょう。
