importjava.io.IOException;
importjava.net.URI;
importjava.net.URISyntaxException;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.FileSystem;
importorg.apache.hadoop.fs.Path;
importorg.apache.hadoop.io.LongWritable;
importorg.apache.hadoop.io.Text;
importorg.apache.hadoop.mapreduce.Mapper;
importorg.apache.hadoop.mapreduce.Job;
importorg.apache.hadoop.mapreduce.Reducer;
importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;
importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
publicclassWordCount {
staticfinalStringINPUT_PATH="hdfs://192.168.56.171:9000/WordCount/word";
staticfinalStringOUT_PATH="hdfs://192.168.56.171:9000/WordCount/out";
publicstaticvoidmain(String[]args)throwsIOException,
InterruptedException,
ClassNotFoundException, URISyntaxException {
Configurationconf=newConfiguration();
finalFileSystemfileSystem= FileSystem.get(newURI(INPUT_PATH),conf);
finalPathoutPath=newPath(OUT_PATH);
if(fileSystem.exists(outPath)) {
fileSystem.delete(outPath,true);
}
finalJobjob=newJob(conf, WordCount.class.getSimpleName());
//打包运行时必须执行的秘密方法
job.setJarByClass(WordCount.class);
// 1指定读取的文件位于哪里
FileInputFormat.setInputPaths(job,INPUT_PATH);
//指定如何对输入文件进行格式化,把输入文件每一行解析成键值对
// job.setInputFormatClass(TextInputFormat.class);
// 2指定自定义的map类
job.setMapperClass(MyMapper.class);
// map输出的类型。如果的类型与类型一致,则可以省略
// job.setMapOutputKeyClass(Text.class);
// job.setMapOutputValueClass(LongWritable.class);
// 3分区
// job.setPartitionerClass(MyPartitioner.class);
//有一个reduce任务运行
job.setNumReduceTasks(1);
// 4TODO排序、分组+
// 5TODO规约
job.setCombinerClass(MyCombiner.class);
// 6指定自定义reduce类
job.setReducerClass(MyReducer.class);
//指定reduce的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
// 7指定写出到哪里
FileOutputFormat.setOutputPath(job,outPath);
//指定输出文件的格式化类
// job.setOutputFormatClass(TextOutputFormat.class);
//把job提交给JobTracker运行
job.waitForCompletion(true);
}
staticclassMyMapperextends
Mapper {
// LongWritable, Text和Text, LongWritable分别是输入与输出的数据类型
protectedvoidmap(LongWritablek1, Textv1, Contextcontext)
// k1指v1的偏移量,v1是指输入的文本数据,有下面的输出语句可得知,
// v1为一行的数据
throwsIOException,
InterruptedException {
System.out.println("k1="+k1+" ,v1="+v1);
//把v1转换成String类型,并以空格为分隔,存储在String字符数组中
finalStringline=v1.toString();
finalString[]splited=line.split(" ");
for(Stringword:splited) {
//使用context.write将此键值对输出,传递给reduce函数。
//而且此键值对类型与上面设定的输出的数据类型相同。
context.write(newText(word),newLongWritable(1L));
System.out.println("Mapper输出");
}
};
}
/*
* Combiner的使用,当map生成的数据过大时,可以精简压缩传给Reduce的数据,又不影响最重点数据,
* reduce的输入每个key值所对应的value都是1,这会占用很大的带宽。
* Combiner的使用可以使在map的输出在给于reduce之前做一下合并或计算,把具有相同key的value做一个计算,
*那么传给reduce的数据就会少很多,减轻了网络压力。
*通过代码可以看出Combiner是用reducer来定义的,因此多数的情况下Combiner和reduce处理的是同一种逻辑。
*只是reduce函数在内部完成的计算,通过Combiner的合并计算,使计算效率大大提高。
*/
staticclassMyCombinerextends
Reducer {
publicvoidreduce(Textk2,
Iterablev2, Contextcontext)
throwsIOException,
InterruptedException {
//显示次数表示reduce函数调用了多少次,表示课有多少个分组
System.out.println("Combiner输入分组");
longtimes= 0L;
for(LongWritablecount:v2) {
times+=count.get();
//显示次数表示k2,v2的键值对数量
System.out.println("Combiner输入键值对
+count.get()
+">");
}
context.write(k2,newLongWritable(times));
//显示次数表示k2,v2的键值对数量
System.out.println("Combiner最终输入键值对
+">");
}
}
staticclassMyReducerextends
// Text, LongWritable和Text, LongWritable分别是输入与输出的数据类型
//且Reducer函数的输入类型对应Mapper函数的输出类型。
Reducer {
//将相同的键的值放入到迭代器v2s中进行遍历。
protectedvoidreduce(Textk2,
Iterablev2s, Contextctx)
throwsIOException,
InterruptedException {
longtimes= 0L;
for(LongWritablecount:v2s) {
times+=count.get();
System.out.println("Reducer输入键值对
+count.get()
+">");
}
ctx.write(k2,newLongWritable(times));
};
}
}