————————————————————————————————————————
前言
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:柘月十七