3、程序示例及註釋
package test;
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.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class MyWordCount {//這是自己寫的一個WordCount和源代碼中是一樣的
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
//這種寫法是新版本纔有的,在hadoop-0.20-之後的寫法
//以前的版本mapper是個接口,hadoop-0.20的時候,將其升爲抽象類,更便於程序的抒寫。
//顯然這裏的Mapper<Object,Text,Text,IntWritable>是範型,其實是
//Mapper<input_Key_Type,input_Value_Type,output_key_type,output_value_type>也就是藉此規定map中用到的數據類型
//這幾種類型除Object之外,其它是jdk中沒有的,這是hadoop對它相應的jdk中數據類型的封裝,
//這裏的Text相當於jdk中的String,IntWritable相當於jdk的int類型,這樣做的原因主要是爲了hadoop的數據序化而做的。
private final static IntWritable one = new IntWritable(1);//聲時一個IntWritable變量,作計數用,每出現一個key,給其一個value=1的值
private Text word = new Text(); //用來暫存map輸出中的key值,Text類型的,故有此聲明
public void map(Object key, Text value, Context context//這裏就是map函數,也用到了範型,它是和Mapper抽象類中的相對應的,此 處//的Object key,Text value的類型和上邊的Object,Text是相對應的,而且最好一
// 樣,不然的話,多數情況運行時會報錯。
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());//Hadoop讀入的value是以行爲單位的,其key爲該行所對應的行號
//因爲我們要計算每個單詞的數目,默認以空格作爲間隔,故用StringTokenizer輔助做一下字符串的拆分,也可以用string.split("")來作。
while (itr.hasMoreTokens()) {//遍歷一下每行字符串中的單詞,
word.set(itr.nextToken());//出現一個單詞就給它設成一個key並將其值設爲1
context.write(word, one);//輸出設成的key/value值。
//以上就是打散的過程
}
}
}
public static class IntSumReducer //reduce所在的靜態類
extends Reducer<Text,IntWritable,Text,IntWritable> {//這裏和Map中的作用是一樣的,設定輸入/輸出的值的類型
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) {//由於map的打散,這裏會得到如,{key,values}={"hello",{1,1,1,1,1,1,....}},這樣的集合
sum += val.get(); //這裏需要逐一將它們的value取出來予以相加,取得總的出現次數,即爲匯和
}
result.set(sum); //將values的和取得,並設成result對應的值
context.write(key, result); //此時的key即爲map打散之後輸出的key,沒有變化,變化的時result,以前得到的是一個數字的集合,此時已 經//給算出和了,並做爲key/value輸出。
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration(); //取得系統的參數
if (args.length != 2) { //判斷一下命令行輸入路徑/輸出路徑是否齊全,即是否爲兩個參數
System.err.println("Usage: wordcount <in> <out>");
System.exit(2); //若非兩個參數,即退出
}
Job job = new Job(conf, "My Word Count,Ha Ha ~");//此程序的執行,在hadoop看來是一個Job,故進行初始化job操作
job.setJarByClass(MyWordCount.class); //可以認爲成,此程序要執行MyWordCount.class這個字節碼文件
job.setMapperClass(TokenizerMapper.class); //在這個job中,我用TokenizerMapper這個類的map函數
job.setReducerClass(IntSumReducer.class); //在這個job中,我用IntSumReducer這個類的reduce函數
job.setOutputKeyClass(Text.class); //在reduce的輸出時,key的輸出類型爲Text
job.setOutputValueClass(IntWritable.class); //在reduce的輸出時,value的輸出類型爲IntWritable
FileInputFormat.addInputPath(job, new Path(args[0]));//初始化要計算word的文件的路徑
FileOutputFormat.setOutputPath(job, new Path(args[1]));//初始化要計算word的文件的之後的結果的輸出路徑
System.exit(job.waitForCompletion(true) ? 0 : 1);
//這裏就是真正的去提交job到hadoop上去執行了,意思是指如果這個job真正的執行完了則主函數退出了,若沒有真正的執行完就退出了,
//則爲非法退出
}
}