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源码官方解读文档
有不足之处,希望留言指正!