新人SEの学習記録

14年度入社SEの学習記録用に始めたブログです。気づけば社会人3年目に突入。

学習記録:Hadoop

[学習記録] Hadoop

内容:8章 MapReduceプログラミングの基礎 〜Javaによる開発〜

JavaによるMapReduceの実装
  • MapReduceフレームワーク
    • フレームワークなので、規定された枠組みにそってアプリケーションのロジックを記述していく必要
    • 初めてHadoopでアプリケーションを記述する際には書きにくいと感じるかもしれないが、サンプルを書いて慣れていく
  • 開発のポイント
    • コンポーネントの役割を把握
      • InputFormat:入力フォーマットの定義
      • Mapper:Map処理
      • Reducer:Reduce処理
      • OutputFormat:出力フォーマット
      • Job:全体を統括するクラス
      • RecordReader:データをレコード毎に読み出してMap処理に渡す
      • RecordWriter:ジョブの出力キーバリューを受け取り出力する
      • OutputComitter:MapReduceジョブの完了処理を行う
    • プログラムは大きく分けて以下の3つの部分からなる
      • Mapper
      • Reducer
      • メイン処理
ソースコードからのプログラム実行(WordCount.java
  • Mapper
public static class TokenizerMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
  private final static IntWritable one = new IntWritable(1);
  private Text word = new Text();

  public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    StringTokenizer itr = new StringTokenizer(value.toString());
    while (itr.hasMoreTokens()) {
      word.set(itr.nextToken());
      context.write(word, one);
    }
  }
...
}
    • LongWritable, IntWeitable, Text
      • Hadoop用のデータ型
      • とりあえずはIntegerやStringと同じものだと思っておけばよい(詳しくは後述)
    • mapメソッド
      • 入力として、(<バイトオフセット>、<一行分のテキスト>)、というキーバリューが渡される
      • キーとして渡されるLongWritable型のデータは、その行がファイル先頭から何バイト目にあるかというバイトオフセット値
      • このバイトオフセット値はMapperの処理では通常使わない
    • mapメソッド
      • Tokenizerを利用して文字列を単語に分解
      • (<単語>、1)というキーバリューをReducerに渡すレコードとして出力
      • 出力には、引数のContextクラスのwriteメソッドを利用
      • 出力データはキーによってソートされ、同じキーを持つレコードが同じReducerに渡されることになる
  • Mapper API
    • org.apache.hadoop.mapreduce.Mapper:Mapperを実装するためのベースとして用意されているクラス
    • ユーザはこのクラスを継承して、自分のアプリケーションを実装
    • オーバライドするメソッド
      • map
      • setup:Mapタスク前の処理を定義
      • cleanup:〜〜後の〜〜
  • Reducer
public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
  private IntWritable result = new IntWritable();

  public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
    int sum = 0;
    
    for (IntWritable val: values) {
      sum += val.get();
    }
    result.set(sum);
    context.write(key, result);
  }
}
    • reduceメソッド
      • 入力データとして(<単語>、<出現回数のイテレータ>)とコンテキストが渡される
      • MapからReduceの間のShuffle処理の結果として、同じキーについてのバリューはイテレータで全て網羅される
      • 上記のコードでは単に単語ごとに出現回数を合計し、(<単語>、<出現回数>)というキーバリューを出力
  • Reducer API
    • Mapperとほとんど同じ構造
    • setup, cleanup
Writable
  • Text, IntWritable...
    • Hadoopがデータ入出力のために用意
    • Writableインタフェースの実装
    • インスタンスは1度だけ初期化され、あとはsetメソッドで値をかえつつ変数は使い回す
    • mapやreduceメソッドが呼ばれる回数は非常に多いので、インスタンスを初期化するような短い時間を節約することも重要
  • その他のWritable
HadoopのWritable Javaのデータ型
BooleanWritable boolean
BytesWritable byte[]
DoubleWritable double
FloatWritable float
IntWritable int
LongWritable long
ShortWritable short
Text String
LongWritable size = new LongWritable(10L);
mainプログラム
  • サンプルプログラム内での実装
    • 宣言部分:public class WordCount extends Configured implements Tool { ... }
    • mainメソッド内:int res = ToolRunner.run(new Configuration(), new WordCount(), args);
    • オプション引数を処理してConfigurationに設定値を格納し、MapReduceジョブを起動
  • ToolRunner
    • Hadoopで利用できるGenericOptionsParserで共通オプション引数を解析
    • Configurationインスタンスにその結果を格納
    • アプリケーション本体であるTool実装のrunメソッドを呼び出し
    • 共通オプションとは以下
オプション 意味
-conf <設定ファイル名> Configurationにロードする設定ファイルのパス指定
-D <プロパティ=値> 指定プロパティに値を格納
-fs(-jt) NameNode(JobTracker)を指定
-files(-libjars, -archives) <ファイル名> 分散キャッシュで配付する(jar, アーカイブ)ファイルの指定