MapReduceのJava実装Apache Hadoopを使ってみた:いま再注目の分散処理技術(後編)(2/3 ページ)
最近注目を浴びている分散処理技術「MapReduce」の利点をサンプルからアルゴリズムレベルで理解し、昔からあるJava関連の分散処理技術を見直す特集企画(編集部)
前編で紹介したプログラムをHadoopで実装
それでは、前編で紹介した「文章で使用されている英字をカウントする」プログラムをHadoop用に作成してみましょう。Hadoopのサンプル「wordcount」のソースコードを参考にして作成しました。この特集では、Hadoopを使ったプログラムの作成方法を紹介することに主眼を置いていますので、これから作成するプログラムはデフォルトの状態で実行します。
まず、パッケージ用のディレクトリを作成します。ここで作成するクラスはsampleパッケージに含めることにしましょう。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
■前編のメインとなるクラスはどうだった?
次に、メインとなるクラスとして、sample.CharCountクラスを用意しますが、その前に前編で作成したMapReduceCharCounterAppクラスをもう一度見ておきましょう。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
MapTaskクラスやReduceTaskクラスからインスタンスを生成して利用しています。
■Hadoopの場合のメインとなるクラス
sample.CharCountクラスでは、自分では各クラスのインスタンスを生成せずに、どんなクラスを利用するのかの設定だけします。具体的に見てみましょう。
sample.CharCountクラスは、Hadoopの提供するorg.apache.hadoop.util.Toolインターフェイスを実装します。main()メソッドでは、org.apache.hadoop.util.ToolRunnerクラスを使って、org.apache.hadoop.util.Toolインターフェイスを実装したクラス(ここでは、sample.CharCountクラス)のrun()メソッドが実行されるようにします。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
このクラスは、基本的で、お決まりの処理をしているだけです。run()メソッド内では、org.apache.hadoop.mapred.JobConfクラスのインスタンスのみ生成し、後は、「MapクラスはsetMapperClass()メソッドで指定したり、ReduceクラスはsetReducerClass()メソッドで指定したりするだけだ」という点に注目してください。
■Hadoopだと簡単なところはイロイロある
さて、今回の例では、keyとなる1文字はorg.apache.hadoop.io.Textクラスで表現することにし、valueとなる値はorg.apache.hadoop.io.IntWritableクラスで表現することにします。前編では、「'a', 1」というペアを表現するために、MapEntryクラスを作りました。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
しかし、Hadoopでは、JobConfクラスのsetOutputKeyClass()メソッド、setOutputValueClass()メソッドを使って指定するだけです。
またHadoopでは、Mapper→Reducerとデータが流れていくので、それぞれのフェイズで処理を行うクラスをsetMapperClass()メソッドなどで登録します。ここでは、Mapperにはsample.MapClassクラス、Reducerにはsample.Reduceクラスを登録しています。
ところで、setCombinerClass()メソッドというのがあることにも気が付きます。Hadoopでは、Mapperの出力をReducerへ渡す前に結合するクラスをユーザーが「Combiner」として指定できるようになっています。Combinerには、普通はReducerと同じクラスを登録すればいいので、ここではsample.Reduceクラスを指定しています。
なお、APIドキュメントがありますから、詳細はそちらを参考にしてください。
■前編のMapperクラスはどうだった?
次に、Mapperクラスを作成します。先に前編のMapTaskクラスを見ておきましょう。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
■Hadoopの場合のMapperクラス
これと対応するsample.MapClassクラスは、次のようになります。MapTaskクラスではbyte型で1文字ずつ取り出していましたが、今回はString型で1文字ずつ取り出し、org.apache.hadoop.io.Text型のデータへセットしています。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
また、MapTaskクラスでは値として「1」を使っていましたが、ここではorg.apache.hadoop.io.IntWritable型のフィールド「one」が参照する値を指定しています。oneは1を値に持つIntWritable型オブジェクトを参照していますから、このクラスはMapTaskクラスと実質的には同じことをしているのが分かるはずです。
■前編のReducerクラスはどうだった?
次はReducerクラスです。ここでも先に前編のReduceTaskクラスを見ておきましょう。次のとおりです。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
■Hadoopの場合のReducerクラス
これと対応するsample.Reduceクラスは次のようになります。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
ReduceTaskクラスでは、ReduceInputクラスを自前で用意しましたが、Hadoopの場合は、reduce()メソッドに、Iterator<IntWritable>型で計算対象のデータリストが渡されます。そのため、これを使ってkeyの文字が何回現れたかをwhile文で計算をしています。こちらも、ReduceTaskクラスと実質的に同じ処理をしていることが分かるはずです。
前編では、MapTaskクラスやReduceTaskクラスが連携しやすくなるようにほかのクラスを用意しました。しかしHadoopでは、メインとMapper、Reducerクラスだけ自作すればプログラムを実行できます。
次ページでは、Hadoopを使ったプログラムをコンパイルして実行し、さらにHadoop用のEclipseプラグインについても紹介します。
Copyright © ITmedia, Inc. All Rights Reserved.