天天看點

Hadoop 學習一

        最近在學習 hadoop , 這是一個非常優秀的分布式架構 , 在學習的過程中也遇到了很多的問題 , 幾度讓人崩潰 , 我現在說說我遇到的問題 , 現在記錄下來和以後友善翻閱 , 同時也希望給在剛剛學習hadoop的朋友們一點小小的幫助。

        我在看了hadoop自己的WordCount Demo後,自己也寫了一個小Demo,但是遇到了問題 ,下面我先說一下問題所在:

         我在本地建立 了一個檔案夾(in)作為輸入檔案夾,檔案夾内建立了兩個文本檔案 (1.txt    2.txt)

我的輸入檔案内容如下:

1.txt 

    hello hadoop

    hello java

    hello C++

2.txt

對于這兩個檔案我們期望得到的答案應該是:

    hello    5

    hadoop    2

    java    2

    C++    1

但是我得到的結果卻是這樣的:

    C++ 2

    hadoop 3

    hello 8

    java 3

這對于一個初學者來說不是很讓人崩潰嗎,一開始我以為我程式寫錯了,但是我檢查了很多遍,還和hadoop自帶的程式對比了,保證沒有出現錯誤,但是是什麼地方出錯了呢,我試過很多方法,不知道是什麼地方的問題。困擾了很久,在我使用 linux指令 ls 的時候想起來了,可能是這樣的問題。下面看一張圖檔:

Hadoop 學習一

從上面的圖檔中,我們看一看到我的輸入檔案夾 in内不隻有我們認為隻有的1.txt 和2.txt 檔案,還多了 1.txt `和2.txt` ,這樣結果肯定就不正确了。

錯誤原因: 

因為我是手動的在in檔案夾内建立了這兩個文本檔案, 原來在我建立檔案的同時生成了兩個該檔案的副本,這樣就出現了我一開始出現的問題,由于是剛開始使用 ubuntu系統 ,不熟悉裡面的機制,相信可能會有很多初學hadoop的朋友會遇到這樣的問題,希望會給大家一些幫助。

package cn.edu.ytu.botao.wordcount;

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
/**
 * 單詞計數
 * @author botao
 *
 */
public class WordCount {
	
	/**
	 * map 過程
	 * 繼承Mapper接口 設定map的輸入類型為 <Object,Text>
	 * 輸出類型為<Text. IntWritable>
	 */
	public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>{
		
		//one 表示單詞出現一次
		private final static IntWritable one=new IntWritable(1);
		//word 用于存儲切下的單詞
		private Text word=new Text();
		
		/**
		 * 重寫map()方法
		 */
		@Override
		protected void map(Object key, Text value, Context context)
				throws IOException, InterruptedException {
			// TODO Auto-generated method stub
			//super.map(key, value, context);
			
			//對value(要計數的檔案進行單詞切割) 進行切分  
			StringTokenizer tokenizer=new StringTokenizer(value.toString());
			//将切割後的單詞取出  輸出
			while (tokenizer.hasMoreTokens()) {
				word.set(tokenizer.nextToken());
				//map 輸出格式  <Text,IntWritable>
				context.write(word, one);
			}
		}
		
		/**
		 * reduce 過程
		 * 繼承Reducer接口 設定輸入類型為 <Text,IntWritable> (該輸入類型正為 mapper 的輸出類型)
		 * 輸出類型為: <Text,IntWritable>
		 */
		
		public static class SumReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
			//numResult 記錄單詞的頻數
			private IntWritable numResult=new IntWritable();
			
			/**
			 * 重寫reduce()方法
			 */
			@Override
			protected void reduce(Text key, Iterable<IntWritable> values,
					Context context)
					throws IOException, InterruptedException {
				// TODO Auto-generated method stub
				
				int  sum=0;
				//對擷取的<key,value-list> 計算value的和
				for (IntWritable val : values) {
					sum+=val.get();
				}
				
				//将頻數存放到numResult 中
				numResult.set(sum);
				//收集結果
				context.write(key, numResult);
			}
		}
	}
}      

繼續閱讀