WordcountMap
package com.aimuti.hadoop.mapreduce;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/*该类要让maptask来调用,继承了一个父类,有四个泛型.读数据的公共操作都封装好了
*它会读取数据后传到这个程序中,以key/value的形式进行数据传递
*Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
*KEYIN:mapreduce框架所读取到的一行文本的起始偏移量
*VALUEIN:mapreduce所读的一行文本的内容
*KEYOUT:用户自定义逻辑处理完后输出的数据中的key(在这指的是单词)
*VALUEOUT:用户自定义逻辑处理完后输出的数据的value值(这里值单词出现次数)
*无论是KEYIN还是KEYOUT都要经过网络传输,所以必须经过序列化
*Long写成LongWritable String写成Text
*/
public class WordcountMap extends Mapper<LongWritable,Text,Text,LongWritable>{
/*编写业务逻辑,重写map方法.
*maptask会对每一行输入数据调用自定义map方法
*key:指一行的偏移量 value:指一行的内容
*/
protected void map(LongWritable key, Text value,Context context)
throws IOException, InterruptedException {
//拿到一行内容,将maptask传来的内容先转换为String
String line = value.toString();
//根据空格将这一行内容切分为单词
String[ ] words = line.split(" ");
/*把一行内出现的任意单词都将次数写为1,相同的也写为1 ("a","1") ("a","1")
*单词只要出现一次,就计数为1,等待reduce阶段再去统计,因为reduce的统计是有范围的,
*所以一定范围内相同的单词计数为1,相同的单词回到一个文件中去,再进行叠加即可
*/
//吧单词输出为<单词,1>的形式
for(String word : words){
//用mapreduce框架提供的上下文对象写出单词,随后maptask分发数据的时候是按照单词分发的,
//所以key是单词,相同的单词会发给相同的reducetask.
context.write(new Text(word),new LongWritable(1));
}
}
}
WordcountReduce
package com.aimuti.hadoop.mapreduce;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/*该类是让reducetask来调用的,Reducer<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
*KEYIN,VALUEIN对应mapper输出的KEYOUT,VALUEOUT类型
*KEYIN对应的是单词,VALUEIN对应的是输出单词的次数1
*KEYOUT,VALUEOUT是自定义reducer逻辑处理结果的输出类型
*那么reduce输出的结果是单词和它的总次数(根据业务情况决定)
*/
public class WordcountReduce extends Reduce<Text, LongWritable, Text, LongWritable>{
/*key是一组相同单词key/value对中的key,这个是maptask分发的结果
*比如<hello,1><hello,1><hello,1><hello,1><hello,1><hello,1>
*但是reducetask是有范围的,还有可能是<world,1>
*reducetask为了统计单词的个数,在调用这个方法时应该把向的单词作为一组来调用一次
*key:hello value:1+1+1.. 第二个参数是迭代器,用来迭代结果,reducetask就可以统计单词总次数了
*/
protected void reduce(Text key, Iterable<LongWritable> values,
Context context) throws IOException, InterruptedException {
//计数,对单个单词进行合并计数
Long count = 0L;
for(LongWritable value : values){
count += value.get();
}
//讲一个单词和它出现的次数写进xontext
context.write(key,new LoginWritable(count));
}
}
WordcountDriver
package com.aimuti.hadoop.mapreduce;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/*写好的map与reduce程序,需要一个启动类
*然后就可以打包到每个节点上进行启动
*相当于yarn集群的客户端,再次封装相关参数
*指定jar包,最后交给yarn
*/
public class WordcountDriver{
public static void main(String[ ] args) throws Exception{
//封装成一个job对象(封装了mapreduce的相关参数)
Configuration conf = new Configuration();
//conf.set("fs.defaultFS","fiel:\\");
//conf不用设置参数? 将mapreduce程序发布到Linux中,Linux中节点都有这个hadoop配置,
//到时会自动读取conf.set("mapreduce.framework.name","yarn")
Job job = Job.getInstance(conf);
//指定本程序的jar包所在的本地路径
job.setJarByClass(WordcountDriver.class);
//指定本业务job要是用的mapper业务类
job.setMapperClass(WordcountMap.class);
job.setReduceClass(WordcountReduce.class);
//指明mapper和reducer的输出key/value类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job,new Path(arg[0]));
//指定job的输出结果所在目录
FileOutputFormat.setOutputPath(job,new Path(arg[1]));
//true代表的是要把集群返回的信息打印出来
//completion表示集群运行成功还是失败
boolean complection = job.waitForCompletion(true);
System.exit(compliection?0:1);
}
}
将项目打成jar包,发送到Linux上,在Linux中运行jar.