————————————————————————————————————————
前言
WordCount算是我们学习hadoop的第一分布式计算程序了,那么把它大致的过程都啃透了将对学习后面的相关知识很有必要。WordCount1.0 代码详解,下面将分析一个2.0版本的“WordCount”的实现任务,相信自己,加油!
任务描述
主要梗概:对如下的样本数据进行编程实现数据的清洗和排序;
Zhangsan 90 83 88
Lisi 83 76 73
Wangwu 84 81 77
Zhaoliu 77 67
Chentian 78 91 82
Liutao 83
具体要求如下:
- 将文件中的空行清洗掉;
- 将文件中的不符合规则的内容清洗掉(每行内容一定要有四个字段);
- 对清洗后的数据进行统计,计算每个同学的总成绩和平均分,最终输出的形式为: 姓名 总成绩 平均分
- 对清洗后的数据进行排序处理,按照学生的总成绩由小到大进行排序,输出的形式仍然为: 姓名 总成绩 平均分
任务要求就这么多,你是否已经有思路了?不管怎么样,不着急往下看分析过程,先捋捋思路或者自己试着完成它再往下看看,加油相信自己!
任务分析
这里就当你已经对WordCount程序了解了个大概了,如果还没有点这里。既然上面的任务分点了,那么接下来也按点分析:
- 要把空行清理了,那么把输出字符是“\n”的筛选掉就可以了。
- 要把不合理的内容清洗掉,换个思路来,我们把合理的内容留下来就可以了;对每条数据截取字段后放到数组,那么数组的长度是4,长度不是4的都筛选掉。
- 对数组元素进行计算并输出,难点来了(画起来喔,要考,嘻嘻嘻)“输出三个字段”,大致实现过程:合并。没错,就是二合一,这样就可以看作两个了。
- 重点又来了,记得圈起来要考的呢,嘻嘻嘻!那就是排序了,难不难?相信自己!排序是这样的,实在太重要了,所以“借一步说”,往下看:
MapReduce默认排序规则
它是按照key值进行排序的,如果key为封装的int为IntWritable类型,那么MapReduce按照数字大小对key排序;
如果Key为封装String的Text类型,那么MapReduce将按照数据字典顺序对字符排序。
代码实现
具体代码如下啦
另外附上程序执行过程的一些重要注意事项,点这里!
import java.io.IOException;
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 Score {
public static class AverageMap extends Mapper<Object,Text,IntWritable,Text>{
public void map(Object key,Text value,Context context) throws IOException,InterruptedException{
String st= value.toString();
//清洗空行
if(st == "\n") {
return;
}
String[] score = st.split(" ");
//清洗不合理数据
if(score.length != 4) {
return;
}
//数据统计,求和以及求均值
int Chinese = Integer.valueOf(score[1]);
int Math = Integer.valueOf(score[2]);
int English = Integer.valueOf(score[3]);
int total = Chinese+Math+English;
int averageScore = total/3;
//因为需要按总分进行排序,所以将总分total以key字段输出,名字和平均分以Text类型value输出(系统默认按照key(IntWritable类型)字段以小到大进行排序)
context.write(new IntWritable(total),new Text(score[0]+" "+averageScore)); //“ ” 包含三个空格
}
}
/*
* 到这里的map函数输出内容如下:
* <232,lisi 77>
* <242,wangwu 80>
* <251,shentian 83>
* <261,zhangsan 87>
*/
public static class AverageReduce extends Reducer<IntWritable,Text,Text,Text>{
public void reduce(IntWritable key,Iterable<Text> values,Context context) throws IOException,InterruptedException{
//将values遍历出来,对(总分,姓名,平均分)字段顺序进行重置(姓名,总分,平均分)
for(Text t : values) {
String[] tt = t.toString().split(" ");
//字段重置,将key字段(总分)设为字符串类型,然后和平均分进行合并为Text输出
String total = String.valueOf(key.get());
//这里的key字段设为Text类型,value也是
context.write(new Text(tt[0]),new Text(total+" "+tt[1])); //“ ” 包含三个空格
}
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
if (otherArgs.length != 2) {
System.err.println("Usage: wordcount <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "AverageScore");
job.setJarByClass(Score.class);
job.setMapperClass(AverageMap.class);
//job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(AverageReduce.class);
//map函数于reduce函数中的输出的类型不一致,需要指定map的输出类型,否则会出现异常(这里也是与wordcount不一样的地方)
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
任务最终效果
程序执行结果最终如下:
若有不足之处望留言!
——————END———————
Programmer:柘月十七