学习Hadoop第一个MapReduce程序WordCount的详解

WordCount官方代码的详解


作为小白的我初次在hadoop里接触mapReduce程序,难免会有些费解以及难懂代码所蕴含的意思,经过自己查阅资料以及消化,便得到下面代码的的解释:

package homework;

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 WordCount { 
	/*
	 * 假设需要统计的内容为:
	 * hello wordcount good
	 * good wordcount nice
	 * 
	 * 在进行map方法统计之前系统会进行预处理,分割成<key,value>
	 * <0,hello wordcount good>
	 * <20,good wordcount nice>
	 * 注:每行都分割一堆键值对的形式,有多少行就执行多少次mapper方法进行分割
	 * 
	 * Mapper的前两个参数Object、Text是输入参数类型<Object,Text>,后两个参数Text、IntWritable是输出参数类型<Text,IntWritable>
	 */
	//map部分
	public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable>{ 
		//创建一个不赋值、且为静态变量one,数值为1,意思是分割后每个单词都记录为1个
		private final static IntWritable one = new IntWritable(1); 
		//创建一个Test类型的变量word,用于记录后面把分割后的字符
		private Text word = new Text();
		//key是输入参数的键,value是输入参数的值,context是设置map的输出值
		public void map(Object key, Text value, Context context ) throws IOException, InterruptedException {
			//StringTokenizer是一个用来分隔String的应用类,在这里是先把value的Text类型转为String类型再创建一个StringTokenizer类的分割对象itr
			StringTokenizer itr = new StringTokenizer(value.toString()); //默认以空格,回车\r,换行\n,制表符\t和换页符\f
			//while循环,判断条件是hasMoreTokens,返回表示是否还有分隔符的boolean类型
			while (itr.hasMoreTokens()) { 
				//itr.nextToken():返回当前位置到下一个分隔符的字符串,这里整体就是把分割出来的字符串再次转换为Text类型的word对象
				word.set(itr.nextToken()); 
				//设置进行mapper方法后的输出值
				context.write(word, one); 
				} 
			} 
		} 
	/*
	 * 到reduce部分
	 * 到这里的内容应为:
	 * <hello,1>
	 * <wordcount,1>
	 * <good,1>
	 * <good,1>
	 * <wordcount,1>
	 * <nice,1>
	 * 
	 * Reduce部分同样有四个参数,前两个是输入参数类型,如:<hello,1>,后面两个是输出参数类型
	 */
	public static class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable> { 
		//reducer是负责数据合并的,那么会将具有相同key的内容合并一起
		//这里的第二个参数实际上类似于一个数组,数组元素类型为IntWritable
		//实际输入的内容转换为:
		/*
		 * <hello,[1]>
		 * <wordcount,[1,1]>
		 * <good,[1,1]>
		 * <nice,[1]>
		 * 
		 * 这里有多少个键值对,reduce方法就执行多少次进行数量统计
		 */
		//创建一个私有的空的IntWritable对象,用于后面做单数统计个数
		private IntWritable result = new IntWritable(); 
		//这里的参数与上面的map方法类似,但是第二个参数是一个类似于IntWritable类型的values数组,context用于设置输出值
		public void reduce(Text key, Iterable<IntWritable> values, Context context ) throws IOException, InterruptedException {
			//初始化单词统计数量
			int sum = 0; 
			//遍历数组里的元素进行相加,便得到单词出现的次数
			for (IntWritable val : values) { 
				//用IntWritable类型的val变量遍历出values数组的元素需要转换成int类型再进行相加,用IntWritable类的get方法的该对象的int类型
				sum += val.get(); 
				} 
			//得到单词出现的次数sum再而用IntWritable的result对象把它设置为IntWritable类型
			result.set(sum); 
			//最后输出reduce的结果,如<wordcount,2>
			context.write(key, result); 
			} 
		} 
	//主函数部分
	public static void main(String[] args) throws Exception {
		/*
		 *Configuration这个类是作业的配置信息类,任何作用的配置信息必须通过Configuration传递,
		 * 因为通过Configuration可以实现在多个mapper和多个reducer任务之间共享信息
		 */
		Configuration conf = new Configuration(); 
		//配置程序函数的输入参数,将输入参数放置到字符串数组otherArgs中
		String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 
		//如果程序的输入不是两个就会退出并打印"Usage: wordcount <in> <out>"提示信息
		if (otherArgs.length != 2) { 
			System.err.println("Usage: wordcount <in> <out>"); 
			System.exit(2); 
		} 
		//设置mapreduce任务的代号,“word count”代号可以随意取
		Job job = new Job(conf, "word count"); 
		//设置jar包程序运行时的主类名称,与类名吻合
		job.setJarByClass(WordCount.class); 
		//设置程序负责mapper功能的类名,与上TokenizerMapper符合
		job.setMapperClass(TokenizerMapper.class); 
		
		//job.setCombinerClass(IntSumReducer.class); 
		
		//设置程序负责reducer功能的类名,与IntSumReducer上符合
		job.setReducerClass(IntSumReducer.class); 
		//设置reduce函数的输出键类型
		job.setOutputKeyClass(Text.class); 
		//设置reduce函数的输出值类型
		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); 
		} 
	}

Mapreduce源码官方解读文档
有不足之处,希望留言指正!

发布了29 篇原创文章 · 获赞 8 · 访问量 4666

猜你喜欢

转载自blog.csdn.net/weixin_43716338/article/details/103034898