最近在学习 hadoop , 这是一个非常优秀的分布式框架 , 在学习的过程中也遇到了很多的问题 , 几度让人崩溃 , 我现在说说我遇到的问题 , 现在记录下来和以后方便翻阅 , 同时也希望给在刚刚学习hadoop的朋友们一点小小的帮助。

        我在看了hadoop自己的WordCount Demo后,自己也写了一个小Demo,但是遇到了问题 ,下面我先说一下问题所在:

         我在本地新建 了一个文件夹(in)作为输入文件夹,文件夹内新建了两个文本文件 (1.txt    2.txt)

我的输入文件内容如下:

1.txt 

    hello hadoop

    hello java

    hello C++

2.txt

    hello hadoop

    hello java


对于这两个文件我们期望得到的答案应该是:

    hello    5

    hadoop    2

    java    2

    C++    1

但是我得到的结果却是这样的:

    C++ 2

    hadoop 3

    hello 8

    java 3


这对于一个初学者来说不是很让人崩溃吗,一开始我以为我程序写错了,但是我检查了很多遍,还和hadoop自带的程序对比了,保证没有出现错误,但是是什么地方出错了呢,我试过很多方法,不知道是什么地方的问题。困扰了很久,在我使用 linux命令 ls 的时候想起来了,可能是这样的问题。下面看一张图片:

wKioL1QK-6DT--h3AAEHmL3F80M646.jpg


从上面的图片中,我们看一看到我的输入文件夹 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);
			}
		}
	}
}