2009年10月16日金曜日

Hadoopで何ができるのか

こんにちは、yoshitsuguです。

仕事でHadoopのプログラムをゴリゴリやっているわけなんですが、例えば「何か簡単なサンプルアプリを書け。word count以外で、だ。」と言われると結構困ってしまいます。

HadoopというよりMap/Reduceというアルゴリズムでできることとは、一体なんでしょうか?

ある程度DBのシステムを組んだことがある人には、
  • Map≒WHERE + GROUP BY(※集約キー指定のみ)
  • Reduce≒GROUP BY(※キーでデータが集約されてくる), COUNT(), SUM(), MAX(), MIN()などの集約関数
であるという説明が案外わかりやすい気がします。
(私の業務では、DBに近い使い方が結構多いからかもしれません)

具体例で示します。
次のプログラムはApacheのアクセスログから404アクセスしたクライアントのIPアドレスとリクエストURLを抜き出してカウントする処理です。

------- Map処理(クラス定義等は省略) ---------------
/**
 * mapメソッドです。<BR>条件を絞って key, valueの組を作ります。
 */
public void map(LongWritable key, Text value, Context context) {
    String code = getCode(value); //
    if (code.matches("404")) {
        // URLを抜き出してvalueとする。
        String url = getURL(value);
        String ip = getIP(value);
        // 出力する
        context.write(new Text(ip), new Text(url));
    }
}

------- Reduce処理(クラス定義等は省略) ---------------
/**
 * reduce処理。>br<クライアントIPアドレス毎に要求URLをカウントします。
*/
public void reduce(Text key, Iterable value, Context context) {
    Map urlMap = new HashMap();
    for (Iterator iter = value.iterator();         iter.hasNext();) {
        String url = iter.next().toString();
        Integer count = urlMap.get(url);
        if (count == null) {
            urlMap.put(url, new Integer(1));
        } else {
            urlMap.put(url, new Integer(count.intValue() + 1));
        }
    }
    StringBuilder sb = new StringBuilder();
    Iterator entries = .entrySet().iterator();
    for (Map.Entry entry : entries) {
        sb.append(entry.getKey()).append("\t").append(entry.getValue()).append("\t")
    }
    sb.setlength(sb.length - 1);
    context.write(key, sb.toString);
}


データベースの場合、集約によるCOUNT()ならば数値を加算するのみですが、Hadoopの場合は上記のように文字列を集約してさらに数えたり等いろいろな事ができるのです。

結構お客様から「データベースとの比較データを出せ」などと言われることが多いのですが、データベースの速度もIndexを張っていたりいなかったりやSQLのクエリの仕方次第で大きく変わるので、一概に比較することは難しいと思います。

やはりバッチ処理として、大量データに対するマッチング処理やキーワードを抽出して検索Index作成、ログデータ中のキーワードの頻度測定などの用途が向いていると思います。