EclipseにHadoopの開発環境を作る。

2014/6/13
新しい記事があります。
EclipseでHadoop2.4の開発環境を作る&ワードカウントのプログラムを作成する。

                                                                                                                      • -

Hadoopを実験するにあたって、プログラムが作れる環境を構築した。
構築には、「30 分で NetBeans を使って Hadoop のプログラムを作ってみる」 を参考にさせていただいた。ただし、慣れているEclipse(Juno)を使うことにした。

開発機はMac Book Pro (OSX Lion)。

まず、Eclipseの本家ページより、Eclipse Juno JEEをダウンロードして、抵当な場所に解凍し、wordbenchを開くところまでやる。

次にhadoopの本家サイトより、hadoop-1.1.2をダウンロードし、ホームディレクトリに解凍、以下のようなシンボリックリンクを張った。

Javaプロジェクトの作成

javaパースペクティブJavaプロジェクトを作成する。ここでは、プロジェクト名をhadoopsampleとした。
デフォルトパッケージにMain.javaを作成する

Main.javaは、参考サイトのサンプル(Hadoopのサイトのサンプルと思われる)を移植する。
このMain.javaは、入力ファイルの存在するディレクトリ(Users/tetsuya/input)と、出力を行うディレクトリ(Users/tetsuya/output)を引数に指定して、inputディレクトリにあるファイルをさらって語句のカウントを行い、結果をoutputディレクトリに書き出すもので、これらは実行時の引数として渡す。

import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;



/**
 *
 * Mainクラス
 * 
 * 引数で指定した入力ファイルからWord Countを行う。
 * 
 */
public class Main {

    public static class Map extends Mapper<LongWritable, Text, Text, IntWritable>{
        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
            String line = value.toString();
            StringTokenizer tk = new StringTokenizer(line);
            while(tk.hasMoreTokens()){
                word.set(tk.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable>{
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException{
            int sum = 0;
            for(IntWritable value: values){
                sum += value.get();
            }
            context.write(key, new IntWritable(sum));
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        Job job = new Job(new Configuration(), "wordcount");
        job.setJarByClass(Main.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        job.setMapperClass(Map.class);
        job.setCombinerClass(Reduce.class);
        job.setReducerClass(Reduce.class);

        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

            boolean success = job.waitForCompletion(true);
            System.out.println(success);
    }

}

プロジェクト名を右クリックし、プロパティーを選択、Java Build Pathの「Add External JARs」で、/Users/tetsuya/hadoop直下、Users/tetsuya/hadoop/lib下に存在するjarファイルを追加する。


Main.java実行時にhadoopの実行環境を教えなければならない(ただし、Hadoopとしての分散環境を構築しているわけではないので、Javaアプリとして実行されるだけ)ので、Main.javaの引数とVMオプションを設定する。
Main.javaを選択し、右クリック、プロパティーで、run/ debug Settingsを選ぶ。newをおして、Argumentタブを選択し、以下を設定する。

引数(Argument):/Users/tetsuya/input /Users/tetsuya/output
VMオプション(VM Argument):-Xmx1000m -Dhadoop.log.dir=/Users/tetsuya/hadoop/logs -Dhadoop.log.file=hadoop.log -DHadoop.home.dir=/Users/tetsuya/hadoop -Dhadoop.id.str=host -Dhadoop.root.logger=INFO,console -Dhadoop.policy.file=hadoop-policy.xml

Javaプログラムの実行

User/tetsuya/inputにデータを作成する。

echo aaa bbb ccc bbb > ./input/input.txt

outputフォルダーを作成しておくとエラーが出てしまうので作成しない。

以下がコンソールログ

2013-06-15 10:59:36.264 java[58712:1203] Unable to load realm info from SCDynamicStore
13/06/15 10:59:36 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
13/06/15 10:59:36 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
13/06/15 10:59:36 WARN mapred.JobClient: No job jar file set.  User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
13/06/15 10:59:36 INFO input.FileInputFormat: Total input paths to process : 1
13/06/15 10:59:36 WARN snappy.LoadSnappy: Snappy native library not loaded
13/06/15 10:59:37 INFO mapred.JobClient: Running job: job_local_0001
13/06/15 10:59:37 INFO mapred.Task:  Using ResourceCalculatorPlugin : null
13/06/15 10:59:37 INFO mapred.MapTask: io.sort.mb = 100
13/06/15 10:59:37 INFO mapred.MapTask: data buffer = 79691776/99614720
13/06/15 10:59:37 INFO mapred.MapTask: record buffer = 262144/327680
13/06/15 10:59:37 INFO mapred.MapTask: Starting flush of map output
13/06/15 10:59:37 INFO mapred.MapTask: Finished spill 0
13/06/15 10:59:37 INFO mapred.Task: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
13/06/15 10:59:37 INFO mapred.LocalJobRunner: 
13/06/15 10:59:37 INFO mapred.Task: Task 'attempt_local_0001_m_000000_0' done.
13/06/15 10:59:37 INFO mapred.Task:  Using ResourceCalculatorPlugin : null
13/06/15 10:59:37 INFO mapred.LocalJobRunner: 
13/06/15 10:59:37 INFO mapred.Merger: Merging 1 sorted segments
13/06/15 10:59:37 INFO mapred.Merger: Down to the last merge-pass, with 1 segments left of total size: 32 bytes
13/06/15 10:59:37 INFO mapred.LocalJobRunner: 
13/06/15 10:59:37 INFO mapred.Task: Task:attempt_local_0001_r_000000_0 is done. And is in the process of commiting
13/06/15 10:59:37 INFO mapred.LocalJobRunner: 
13/06/15 10:59:37 INFO mapred.Task: Task attempt_local_0001_r_000000_0 is allowed to commit now
13/06/15 10:59:37 INFO output.FileOutputCommitter: Saved output of task 'attempt_local_0001_r_000000_0' to /Users/tetsuya/output
13/06/15 10:59:37 INFO mapred.LocalJobRunner: reduce > reduce
13/06/15 10:59:37 INFO mapred.Task: Task 'attempt_local_0001_r_000000_0' done.
13/06/15 10:59:38 INFO mapred.JobClient:  map 100% reduce 100%
13/06/15 10:59:38 INFO mapred.JobClient: Job complete: job_local_0001
13/06/15 10:59:38 INFO mapred.JobClient: Counters: 17
13/06/15 10:59:38 INFO mapred.JobClient:   File Output Format Counters 
13/06/15 10:59:38 INFO mapred.JobClient:     Bytes Written=30
13/06/15 10:59:38 INFO mapred.JobClient:   FileSystemCounters
13/06/15 10:59:38 INFO mapred.JobClient:     FILE_BYTES_READ=376
13/06/15 10:59:38 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=97564
13/06/15 10:59:38 INFO mapred.JobClient:   File Input Format Counters 
13/06/15 10:59:38 INFO mapred.JobClient:     Bytes Read=16
13/06/15 10:59:38 INFO mapred.JobClient:   Map-Reduce Framework
13/06/15 10:59:38 INFO mapred.JobClient:     Map output materialized bytes=36
13/06/15 10:59:38 INFO mapred.JobClient:     Map input records=1
13/06/15 10:59:38 INFO mapred.JobClient:     Reduce shuffle bytes=0
13/06/15 10:59:38 INFO mapred.JobClient:     Spilled Records=6
13/06/15 10:59:38 INFO mapred.JobClient:     Map output bytes=32
13/06/15 10:59:38 INFO mapred.JobClient:     Total committed heap usage (bytes)=369238016
13/06/15 10:59:38 INFO mapred.JobClient:     SPLIT_RAW_BYTES=100
13/06/15 10:59:38 INFO mapred.JobClient:     Combine input records=4
13/06/15 10:59:38 INFO mapred.JobClient:     Reduce input records=3
13/06/15 10:59:38 INFO mapred.JobClient:     Reduce input groups=3
13/06/15 10:59:38 INFO mapred.JobClient:     Combine output records=3
13/06/15 10:59:38 INFO mapred.JobClient:     Reduce output records=3
13/06/15 10:59:38 INFO mapred.JobClient:     Map output records=4
true


outputフォルダーを見ると_SUCCESS、part-r-00000ファイルができており、part-r-00000に実行結果が入っている。

aaa     1
bbb     2
ccc     1