小弟今天運行了一個小小的關於map-reduce的WordCount 程序,經過一番搗騰收獲可不小。在這里記錄運行過程中所遇到的一些常見問題,有關於和其他版本不同的地方。
再偽分布式的開發環境下,在集成開發環境中寫好了WordCount 程序,程序源代碼如下:
TokenizerMapper 類:
public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable count = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
StringTokenizer st = new StringTokenizer(value.toString());
while (st.hasMoreTokens()) {
word.set(st.nextToken());
context.write(word, count);
}
}
}
IntSumReducer類的相關代碼如下:
public static class IntSumReducer extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable i : values) {
sum += i.get();// 對單詞為key的計數統計
}
result.set(sum);// 每次set一下都會清空之前的值
context.write(key, result);
}
}
主方法中:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args)
.getRemainingArgs();
System.out.println("the length of otherArgs is:"+otherArgs.length+",\n---the parameters of input at the con is:" + args[0] + "----" + args[1]);
if (otherArgs.length != 2) {
System.err.println("Usage: wordcount <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "word count");
job.setJarByClass(WordCount.class);// jar 包中的主方法入口類
job.setMapperClass(TokenizerMapper.class);// 入口類中的mapper類
job.setReducerClass(IntSumReducer.class);// 入口類中的reducer類
job.setCombinerClass(IntSumReducer.class);// 進行數據lower ruducer的類
job.setOutputKeyClass(Text.class);// 設置好輸出的key 的類型系統會將該類型作為key
job.setOutputValueClass(IntWritable.class);// 輸出的數據類型
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));// 輸入的文件目錄
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));// 輸出的文件目錄
System.exit(job.waitForCompletion(true) ? 0 : 1);// 若系統運行成功, 則返回0 ,否則返回1
}
打好jar包后,將wordcount.jar 拷貝到linux 系統的 /usr/hddemo 目錄下,在開啟集成的條件下,完成以下准備工作:
1、在hdfs 根目錄下創建一個input目錄,用於map 作業啟動時數據的輸入源,即map任務需要數據就將到該目錄下進行讀取並使用默認的TextInoutFormat進行解析
2、在hadoop 目錄下創建一個目錄,用來准備輸入的一些文件,我這里使用的目錄是 input ,其中是將hadoop的一些配置文件放於這里,進行文件拷貝的命令如下所示:
cp ./etc/hadoop/*.xml ./input
3、文件准備好了,就要上傳到hdfs的文件系統中去,因為剛剛我們所創建的目錄是在自己的本地文件系統下,我們要將這些文件上傳到hadoop 的文件系統中去,hadoop 才能找得到數據源,使用一下命令進行文件的上傳
bin/hadoop fs -put ./input/*.xml input 上傳成功如下圖所示:
4、我的wordcount.jar 是放在./usr/hddemo 目錄下,如下圖所示:
5、一切工作准備就緒,接下來就是見證奇跡的時刻,按照視頻或者網上的方法是使用一下命令,小弟見到,嘿,資料還蠻豐富的,於是就快速的敲完命令:
一下是運行一個wordcount 任務的命令:bin/hadoop jar /usr/hddemo/wordcount.jar 包名.WordCount input output
說明:input 指定的是執行map任務是的數據源所在目錄,output 是指定reduce任務 執行完后將結果輸出的目錄
一按下 enter 鍵 ,出乎意料的結果出現了:
這下就奇怪了,按照老師的方法來寫的,參照網上的快照給做的,怎么我就出這么一個奇葩的結果呢?這就暈了---,仔細閱讀代碼后,發現輸入的參數 不等於2,所以應用程序就退出了。這是什么原因呢?於是我就嘗試着將輸入參數的長度打印出了,發現為3,如上圖上示,而且把第一個參數和第二個參數打印出來,結果發現並不像我們想象的一樣, 程序中指定輸入兩個參數,而我們輸入了三個參數,肯定是多輸入了,查看命令行,發現.jar 后面確實是帶了三個參數,難道是這里出現了問題,而且打印的第一參數和第二個參數和輸入的順序一樣,這才發現原來是這里除了問題,那到底哪個參數不要呢?不指定主類,hadoop 他找到的嗎?刪掉一個input 或者output ,那也可定是不行的,那到底哪個參數是不需要的呢?於是帶着猜疑的想法,先將主類的路勁給刪除 跑一邊吧,於是有輸入一下的命令:
bin/hadoop jar /usr/hddemo/wordcount.jar input output
結果奇跡就出現了:程序快樂的跑起來了,也不再悶悶不言了,哈哈,然后查看hdfs 上的out目錄,果然有相應輸出,這就是reduce任務執行完后的輸出:如下所示:
最后閉上眼睛 靜靜的等待 bin/hadoop fs -cat output/* 輸出執行的結果:
結果終於如願啦:
通過以上可以發現,hadoop 2.6 版本當命令行執行作業時,不需要指定主類的具體名稱,而是直接指定輸入的數據目錄和輸出的數據目錄即可,最后需要注意,如果輸出的目錄output在hdfs 上已經有了,則會運行不成功,拋出一下異常:
至此,一個hadoop 的WordCount 程序就這樣如痴如醉的跑起來,希望給hadoop的過客有很大的幫助!