WordCount程序
a b c c
b e a
c e a
a 3
b 2
c 3
e 2
步骤
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
//map阶段
/**
* map类要继承Mapper
* <KEYIN, VALUEIN, KEYOUT, VALUEOUT>
* 先是读取一行,即数据的缩进是keyin,数据是valuein
* KEYIN : 表示Map阶段数据输入的时候的数据类型,在默认的数据读取组件,叫InputFormat,他是一行一行的读取待处理的数据
* 读取一行返回一行给mr程序,这种情况下,keyin就表示每一行的起始偏移量(首行缩进) 他的数据类型是Long
* <p>
* VALUEIN: 表示Map阶段数据输入的时候value的数据类型,在默认的读取组件下,valuein就表示读取的这一行内容 因此数据类型是String
* <p>
* KEYOUT: 表示Map阶段数据输出的key的数据类型 在本案例1中 输出的key是单词 因此数据类型是String
* <p>
* VALUEOUT: 表示Map阶段数据输出的类型 在本案例中 value输出的是数字 因此数据类型是int
* <p>
* String int...是jdk自带的·数据类型 在序列化的时候效率低下 因此hadoop封装了数据类型 即writable结尾的
*/
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
/**
* 这里就是Mapper阶段具体的业务逻辑实现方法,该方法的调用取决于读取数据的组件有没有给mr传入数据
* 如果有的话,每传入一个<k,v>对 就会被调用一次(这个kv对就是代表一行内容)
* (一个个kv对连续传入,直到没有)
*
* @param key
* @param value
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//拿到传入进来的内容,把数据类型转换为String
String line = value.toString();//valuein中的一行
//将这一行内容按照分隔符进行一行内容的切割,切割成一个个的单词
String[] words = line.split(" ");
//遍历数组,没出现一个单词 就标记一个数字1<单词,1>
for (String word : words) {
//使用mr程序的上下文,把mapper阶段处理的数据发送给reduce,让其接收
context.write(new Text(word), new IntWritable(1));
}
}
}
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* 继承Reducer
* 这里是mr程序 reducer阶段
* KEYIN : 就是reducer阶段输入的数据类型 也是map的key的输出 在本案例中就是单词
* <p>
* VALUEIN : 就是reducer阶段输入的数据类型 也是map的value的输出 在本案例中就是数字
* <p>
* KEYOUT : 这是reducer输出的key数据类型 本案例中就是单词
* <p>
* VALUEOUT : 这是reducer输出的value数据类型 本案例中就是出现的次数
*/
public class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* 重写reduce,这里是单词统计
*
* @param key
* @param values
* @param context
* @throws IOException
* @throws InterruptedException
*
* reduce接受map阶段的数据后,按照key的字典顺序进行排序
* 接着按照key相同作为一组去调用reduce方法
* 本方法的key就是这一组相同kv对的共同k
* 把这一组所有的v作为一个迭代器传入我们的reduce方法
*
* (一组一组传入,直到没有)
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//调用计数器
int count = 0;
//遍历一组迭代器,把每一个数量1累加,就构成了总次数
for(IntWritable value : values){
count += value.get();//get方法把IntWritable-->int类型
}
//把最终的结果输出
context.write(key,new IntWritable(count));
}
}
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.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import java.net.URI;
/**
*这个类就是mr运行时候的主类,本类组装了一些程序运行时的信息
*
*/
public class WordCountDriver {
public static void main(String[] args)throws Exception {
//通过Job这类来封装本次mr的信息
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//指定本次mrjob jar运行的主类
job.setJarByClass(WordCountDriver.class);
//指定本次所用的map和reduce类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReduce.class);
//指定本次mr mapper阶段的输出kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定reduce输出的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//设置输出形成几个文件(有效文件)
//这是数据分区
job.setNumReduceTasks(1);
//指定本次输入数据和输出数据路径
FileInputFormat.setInputPaths(job,"D:\\input");
//ouptu文件夹不能存在,否则会报错
FileOutputFormat.setOutputPath(job,new Path("D:\\output"));
//提交并且监控打印情况
// job.submit(); 只是提交
boolean b = job.waitForCompletion(true);//提交并且监控打印
System.exit(b?0:1);
}
}