MapReduce
-
什么是MapReduce?
MapReduce分布式计算框架
MapReduce是一种分布式计算模型,由Google提出,主要用于搜索领域,解决海量数据的计算问题.
MR由两个阶段组成:Map和Reduce,用户只需要实现map()和reduce()两个函数,即可实现分布式计算,非常简单。
这两个函数的形参是key、value对,表示函数的输入信息。底层依赖于HDFS存储。
- 将大型、复杂的任务分解为许多小型任务同时计算,以提高计算机处理能力。
- 为用户提供接口
- map:映射,将任务分解为多个子任务
- reduce:归约,分解后多任务结果汇总
-
优点:
- 简单的接口就能完成一个分布式程序;
- 良好的扩展性;
- 容错性,廉价PC上使用。
- 适合海量数据离线处理
基本概念
- Mapper
- Reduce
- Job
- MapReduce程序编写后配置成为一个MapReduce作业
- Task
- 分位MapTask和ReduceTask
- JobTracker
- 创建MapTask和ReduceTask
- TaskTracker
- 执行MapTask和ReduceTask
架构设计
-
MapReduce V1
-
Master:JobTracker,初始化作业、创建调度子任务
-
Slave:TaskTracker,执行任务
-
-
MapReduce V2:YARN
执行过程
- input
- split
- map
- shuffle
- reduce
-
map任务处理
1.1 读取输入文件内容,解析成key、value对。对输入文件的每一行,解析成key、value对。每一个键值对调用一次map函数。
1.2 写自己的逻辑,对输入的key、value处理,转换成新的key、value输出。 -
reduce任务处理
2.1 在reduce之前,有一个shuffle的过程对多个map任务的输出进行合并、排序。
2.2写reduce函数自己的逻辑,对输入的key、value处理,转换成新的key、value输出。
2.3 把reduce的输出保存到文件中。
在 Shufflle阶段输入到 reduce阶段之前,会进行分组
默认分组规则就是同一个 key就会进入同一个 reduce方法中,并且这些 同一个key的所有的值将会存储在一个 迭代器values之中,也就是 reduce方法的 第二个参数。
工作原理
(124条消息) MapReduce工作原理详解(学习笔记)_Yage的博客-CSDN博客_mapreduce工作原理
编程模型
- 实现Mapper.map() AppMaster
- 实现Reduce.reduce() MapTask
- Job配置 ReduceTask
Mapper阶段
Mapper的KV类型可自己定义,泛型。
- 自定义Mapper继承自己的父类。
- Mapper输入数据KV对的形式。
- map()重写业务逻辑。
- Mapper输出KV对形式。
- map()方法即MaskTask任务进程对每个KV调用一次。
Reduce阶段
- Reducer继承父类
- 输入数据类型需要对应Mapper输出数据类型KV
- Reduce.reduce()重写
- ReduceTask进程中每一组KV调用一次reduce()
Driver
- 提交上述配置的Mapper和Reducer封装好Job对象。
样例(统计一文件中单词出现的个数)
样例代码
- Mapper
/**
* Mapper<inputkey,inputvalue,outputkey,outputvalue/>
*
* exemple
* input==> hello world our world
* output==> <hello,1><world,1><our,1><world,1>
*
* Mapper
* @author whai_luo
* @Date: 2020/5/19 14:00
*/
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//获取文本
String line = value.toString();
//对进入的text文本进行切片
String[] words = line.split(" ");
//输出到reduce
for (String word:words) {
//循环输出(text,intwritable==1)==>
context.write(new Text(word),new IntWritable(1));
}
}
}
- Reduce
/**
*
* reduce
* exemple
* !!!每一个k2对应一个hash,故相同的word会进入同一个reduce
*
* 经过shuffle过程后 input发生变化
*
*
* input==> <bigdate,1,1
* output==> bigdate 2
*
* @author whai_luo
* @Date: 2020/5/19 14:11
*/
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* reduce汇总
* @param key
* @param values
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
/**
* get==> Return the value of this IntWritable.
* 返回值就是value的每个1
* 每次sum都加上一个1
*/
sum+=value.get();
}
//返回获取到的output
context.write(key,new IntWritable(sum));
}
}
- Job
/**
* @author whai_luo
* @Date: 2020/5/19 14:28
*/
public class MapReduceWCDriver {
public static void main(String[] args) throws Exception {
//配置信息
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//job设置主类(本类)
job.setJarByClass(MapReduceWCDriver.class);
//Mapper reduce设置
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//map输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//最终输出
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//输入输出路径设置
FileInputFormat.setInputPaths(job,new Path("/input/"));
FileOutputFormat.setOutputPath(job,new Path("/input/result"));
//提交
/**
* Submit the job to the cluster and wait for it to finish.
*/
boolean b = job.waitForCompletion(true);
/**
* Terminates the currently running Java Virtual Machine.
*/
System.exit(b?0:1);
}
- 打包运行
hadoop jar @jar包 @main函数包路径
- 运行结果