MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实例进程:
1)MrAppMaster:负责整个程序的过程调度及状态协调。
2)MapTask:负责Map阶段的整个数据处理流程。
3)ReduceTask:负责Reduce阶段的整个数据处理流程。
常用数据序列化类型
为了支持分布式计算和大规模数据处理,在Hadoop包中处理的数据类型对Java的数据类型进行了封装。
Java类型 | Hadoop Writable类型 |
Boolean | BooleanWritable |
Byte | Writable |
Int | IntWritable |
Float | FloatWritable |
Long | LongWritable |
Double | DoubleWritable |
String | Text |
Map | MapWritable |
Array | ArrayWritable |
Null | NullWritable |
MapReduce编程结构
1.Mapper阶段
(1)用户自定义的Mapper要继承hadoop中的Mapper。
(2)Mapper的输入数据是KV键值对形式(KV类型可以自定义)。
(3)具体Mapper阶段的业务代码写在重写的map()方法中。
(4)Mapper的输出数据是KV键值对形式(KV类型可以自定义)。
(5)MapTask进程对每一个<K,V>就调用一次map()方法。
2. Reduce阶段
(1)用户自定义的Reduce要继承hadoop中的Reducer。
(2)Reduce的输入数据类型对应的是Mapper的输出数据类型:KV键值对。
(3)具体Reduce阶段的业务代码写在重写的reduce()方法中。
(4)ReduceTask进程对每一组相同K的<K,V>组调用一次reduce()方法。
3. Driver阶段
相当于YARN集群的客户端,用于提交整个集群到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象。
实操——计算文本中单词出现的次数
1. 创建maven项目,导入依赖
以 Whatever is worth doing is worth doing well 为例:
我们需要完成的Map阶段和Reduce阶段的任务,以及整个mapreduce程序的入口。
对应三个Java类:WordCountMapper、WordCountReducer和WordCountDriver。
创建包 mapreduce.wordcount => 分别创建类WordCountMapper、WordCountReducer和WordCountDriver。
2. WordCountMapper.java:
假设要计算的文本内容如下:(分成两行,行数=map()函数的调用次数)
Whatever is worth doing
is worth doing well
Mapper类的四个参数:
Mapper<LongWritable, Text,Text, IntWritable>
LongWritable:
表示map函数的输入的键值对中的key的类型,值为每行文本的偏移量,第一行的偏移量为23,空格和换行符也算在内。
Text:
代表map函数的输出的键值对的value的类型,值为每一行的文本内容,比如第一行: Whatever is worth doing
Text:
代表输出键值对的key的类型,代表每个单词,第一次调用map(),值就是Whatever
IntWritable:
代表map函数的输出kv键值对的value类型,代表每个单词的出现次数,都是一次
package mapreduce.wordcount;
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;
/**
* LongWritable:表示map函数的输入的键值对中的key的类型,值为每行文本的偏移量
* 第一个Text:代表map函数的输出的键值对的value的类型,值为每一行的文本内容
*
* 第二个Text:代表输出键值对的key的类型,代表每个单词
* IntWritable:代表map函数的输出kv键值对的value类型,代表每个单词的出现次数(1次)
*/
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
//新建Text对象,该对象作为map阶段输出的kv键值对中的key
Text keyOut = new Text();
//新建IntWritable对象,该对象作为map阶段输出的kv键值对中的value
IntWritable valueOut = new IntWritable(1);
//map()方法的调用次数,取决于文本中有几行
@Override
protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
//获取一行文本
String line = value.toString();
//根据单词间的分隔符进行拆分
String[] words = line.split(" ");
//遍历数组
for (String word : words) {
//对输出kv中的key进行赋值
keyOut.set(word);
//map阶段处理完成,进行kv键值对的输出
context.write(keyOut,valueOut);
}
}
}
3. WordCountReducer.java :
reduce()方法的执行次数 = 输入的键值对的个数 = 单词的种类数量
Reducer<Text, IntWritable,Text,IntWritable>的四个参数:
Text:
map阶段输出键值对中的key,值为单词
IntWritable:
map阶段输出键值对中的value,值为1
Text:
reduce阶段输出键值对中的key,值为单词,没变化
IntWritable:
reduce阶段输出键值对中的value,值为累加之后的总次数
在reduce()方法中:
reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context)
Iterable<IntWritable> values 这个参数就是:(is,[1,1])这样的键值对中的[1,1]部分,对这个集合中数据累加即可得到is出现的次数。
package mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.io.Text;
import java.io.IOException;
/**
* 第一个Text:reduce阶段输入的kv键值对中的key,实际上也是map阶段输出的kv键值对中的key,值为单词
* 第一个IntWritable:reduce阶段输入的kv键值对中的value,实际上也是map阶段输出的kv键值对中的value,值为1
* 第二个Text:reduce阶段输出的kv键值对中的key,值为单词
* 第二个IntWritable:reduce阶段输出的kv键值对中的value,值为对应的单词在整个文本中出现的次数。
*/
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
//新建IntWritable对象,作为reduce阶段输出的键值对的value
IntWritable valueOut = new IntWritable();
//Iterable<IntWritable> values 这个参数就是:(is,[1,1])这样的键值对中的[1,1]部分,
// 对这个集合中数据累加即可得到is出现的次数。
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
//单词出现的总次数
int totalCount = 0;
//对单词出现的次数进行累加
for (IntWritable value : values) {
totalCount += value.get();
}
//对reduce阶段输出的value进行赋值
valueOut.set(totalCount);
//reduce阶段同级完成,将结果输出
context.write(key,valueOut);
}
}
4. WordCountDriver.java:
package mapreduce.wordcount;
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.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
//作为整个mapreduce程序的入口 进行相关程序参数的设置
public class WordCountDriver {
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//1. 获取配置信息对象和job对象
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2. 关联Driver类
job.setJarByClass(WordCountDriver.class);
//3. 设置mapper和reducer的类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4. 设置mapper输出的键值对类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5. 设置最终输出(Reducer)的键值对类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//6. 设置文件的输入路径和计算结果的输出路径
//要计算的文件路径,可以同时计算多个文件
Path file = new Path("D:\\Course\\bigdata\\bigdata-file\\word.txt");
Path file1 = new Path("D:\\Course\\bigdata\\bigdata-file\\word2.txt");
FileInputFormat.setInputPaths(job,file,file1);
//设置计算结果的输出路径(这个目录要不存在)
Path outputPath = new Path("D:\\Course\\bigdata\\bigdata-file\\output");
FileOutputFormat.setOutputPath(job,outputPath);
//7. 提交任务进行计算
boolean result = job.waitForCompletion(true);
System.out.println(result ? "任务执行成功":"任务执行失败");
}
}
5. 运行测试
1)文件中内容
2)运行程序