Hadoopコースを攻略しよう(HDInsightによる大量ログ解析編)

2014年4月29日(火)
佐々木 邦暢(@ksasakims)

MapReduceプログラムの作成

では、いよいよログファイル解析のMapReduceプログラムを書いてみましょう。前回の記事でEclipseをインストールしましたので、それを使って今回のお題の一つである

「アクセス数の多いURI: 上位10件」

を、抽出するプログラムを書いてみましょう。

全く0からプログラムを作るのも大変ですから、Hadoop-1.2.1に含まれるサンプル(WordCount.java)をベースに、改造を加えていく形にしたいと思います。

Hadoopのアーカイブファイルの入手

サンプルプログラムは、Hadoopの配布物一式に含まれています。下記のページを参照し、いずれかのミラーサイトからダウンロードしてください。
> http://www.apache.org/dyn/closer.cgi/hadoop/common/

私は、こちらのファイルをダウンロードしてみました。
> http://ftp.tsukuba.wide.ad.jp/software/apache/hadoop/common/hadoop-1.2.1/hadoop-1.2.1.tar.gz

※なお、hadoop-1.2.1-bin.tar.gzにはソースファイルが入っていませんのでご注意。

このファイルを、どこか適当なところに展開してください。私はC:\Users\ksasaki\Downloads\hadoop-1.2.1に展開しました。Windows環境での.tar.gzの展開には、7-ZIP等のツールやCygwinに含まれるGNU Tarを使うのが手軽かと思います。

EclipseにJavaプロジェクトを作成

Eclipseを起動し、File→New→Java ProjectでJavaプロジェクトを一つ作ります。

※記事中の図をクリックすると拡大表示します(一部除く)。

初期状態ではプロジェクトは空っぽです。ここに、先ほど展開したhadoopのサンプルソースファイルをインポートしましょう。

1. ソースフォルダ”src”を右クリックして、”Import…”をクリックします。

2. “General”→”File System”をクリックして、”Next”をクリックします。

3. “From directory:”に、先ほど展開したhadoopアーカイブの”src/examples”フォルダを指定し、”examples”下の”org”をインポート対象としてチェックします。
最下層の”dancing”と”terasort”は不要なのでチェックを外します。
"Finish"をクリックします。

このようになりましたか?WorcCountクラスがあるのがわかると思います。

※私の好きなJava Browsingパースペクティブに切り替えてあります。

このパッケージにはたくさんのサンプルプログラムが含まれているのですが、わかりやすくするためにWordCount以外のクラスはひとまず削除してしまいましょう。すると、下図のようにすっきりとします。

また、インポートしただけの状態では、JAR参照が足りずにコンパイルエラーが出ていますので、参照を追加します。

1. プロジェクトを右クリックして、”Properties”をクリックします。

2. “Java Build Path”→”Libraries”タブ→”Add External JARs”をクリックします。

3. 先ほど展開したhadoop-1.2.1.tar.gzに含まれていた、”hadoop-core-1.2.1.jar”と” commons-cli-1.2.jar”を選択して、「OK」をクリックします。

以上で、WordCountクラスがコンパイルできるようになったはずです。これを元にして、リクエストURIのトップ10を数えてみましょう。

第1段階:下準備

まずは、正しく動かすための下準備です。
WordCount#main()で、Job#setCombinerClass()を呼んでいる箇所がありますが、これをコメントアウトします。単純なワードカウントであれば、ReducerをそのままCombiner(中間集計処理)としても使えますが、最終的にトップ10の抽出処理を行う我々のReducerは、Combinerにはできません。

それから、クラス名あるいはパッケージ名を変えておきましょう。

org.apache.hadoop.examples.WordCount のままだと、Hadoop実行環境にもともと存在する同名クラスが優先されてしまい、自分で書いたクラスが実行されません。

ここでは、クラス名を”UriCount”にしてみました。

第2段階:Map処理の改造

入力ファイル(解析対象のログファイル)は、ある程度の大きさごとに「入力スプリット」に分割され、各入力スプリットがデータノードに割り当てられます。

各データノードでは、この入力スプリットから1行ずつ取り出しては、Mapperのmapメソッドに引き渡します。

Mapperは、TokenizerMapperというネスト型として定義されています。Mapメソッドをちょっと見てみましょう。

valueにログファイルの一行が入ってくるので、これを処理するわけです。WordCountでは、単純にStringTokenizerで単語に分割して、「単語名=1」というkey-valueペアをcontext.write()に渡しています。例えば、以下のような1行があったとすると、

Quick brown fox jumps over the lazy dog

このようなkey-valueペアが生成されるわけです。

Key Value
quick 1
brown 1
fox 1
jumps 1
over 1
the 1
lazy 1
dog 1

我々が実装すべきURIカウントでは、すべての単語を数える必要はありませんから、

  1. 入力レコード(これは前述の通りタブ区切り)をバラしてURIフィールドを取り出す。
  2. そのURIをカウントアップする。

という簡単な処理で良さそうです。こんな感じでしょうか。

public void map(Object key, Text value, Context context)
        throws IOException, InterruptedException {
      String[] fields = value.toString().split("\t");
      // datetime, clientip, user, serverip, uri, timetaken, useragent
      word.set(fields[4]);
      context.write(word, one);
}

# 変更点を最小にすべく”word”変数は名前を変えずにそのまま使っています。

さて、これでWordCount改めUriCountクラスは単語ではなくURIを数えるプログラムになったはずです。「TOP10の算出」処理をまだ実装していませんが、ひとまず動かしてみましょう。こんなとき便利なのが、手元で動くHDInsight Emulatorです。

著者
佐々木 邦暢(@ksasakims)
日本マイクロソフト株式会社

日本マイクロソフト所属。かつては仮想化コンサルタントとして多くのHyper-V案件を担当。その後、オンプレの重力から人類を開放すべくAzure専門のセールス部隊に転身。HPCやHadoop等、大量のリソースを必要とするワークロードで一儲けしようと画策中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています