Mapper
package hadoop.mr.wordcount;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
//Mapper泛型中,前两个是输入数据的类型,后两个是输出数据的类型。都是key和value
//mapreduce的数据输入输出都是以key-value对的形式来封装的。
//key-value就是键值对,一个key对应一个value
//默认情况下,框架传递的输入数据中的key是文本偏移量(可以理解为是第几个字节,从0开始),value内容就是当前行的文本。
//mapreduce需要网络传输,所以数据的序列化是必须的。因为数据类型简单,所以hadoop拥有自己的序列化机制。
//在这里的体现就是,将long类型换成LongWritable,String换成Text。这样用户就不用关系序列化,Hadoop会自己帮助我们完成。
public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
//mapreduce框架每次读一行数据就调用一次该方法。
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//具体业务逻辑写在这里。key是偏移量,value是文本。
String line = value.toString();
String[] words=StringUtils.split(line, " ");//切分单词
for(String word:words) {
context.write(new Text(word), new LongWritable(1));//输出key为单词,value为1,表示1次。
}
}
}
Reducer
package hadoop.mr.wordcount;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class WCReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
//mapreduce框架在完成map后将所有kv丢进Shuffle机制,分类排序后给reduce,reduce对每一个key运行最高方法。
@Override
protected void reduce(Text key, Iterable<LongWritable> values,Context context)
throws IOException, InterruptedException {
long count = 0;
for(LongWritable value:values) {//累加
count+=value.get();
}
context.write(key, new LongWritable(count));//输出到输出文件
}
}
Runner
package hadoop.mr.wordcount;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
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;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/*
* 描述了作业的所有参数,如:
* 使用了那个map类,那个reduce类,输入路径,输出路径
* 输入输出类型等
*/
public class WCRunner extends Configured implements Tool{//标准runner编写
public static void main(String[] args) throws Exception {
int res=ToolRunner.run(new Configuration(), new WCRunner(), args);
System.exit(res);
}
@Override
public int run(String[] arg0) throws Exception {
Configuration conf = new Configuration();
//在eclipse中运行集群需要将整个工程打包成jar后放在工程的根目录下。(可以看一下mapreduce的运行模式
conf.set("mapreduce.job.jar", "wc.jar");
Job job = Job.getInstance();
job.setJarByClass(WCRunner.class);//设置job所用的那些类在那个jar包
job.setMapperClass(WCMapper.class);
job.setReducerClass(WCReducer.class);
job.setOutputKeyClass(Text.class);//reduce的输出
job.setOutputValueClass(LongWritable.class);
job.setMapOutputKeyClass(Text.class);//map的输出
job.setMapOutputValueClass(LongWritable.class);
//使用org.apache.hadoop.mapreduce.lib改包下的类,是新版本的类。
//指定输入数据路径,mapreduce框架会将该目录下所有文件输入
FileInputFormat.setInputPaths(job, new Path("/mydata/input"));
//输出路径,注意不要有该文件夹存在,hadoop会自己创建,否则会报错。
FileOutputFormat.setOutputPath(job, new Path("/mydata/output"));
//提交job,参数为true则会输出运行进度和过程。
return job.waitForCompletion(true)?0:1;
}
}