大数据全知识点讲解之Mapreduce
Mapreduce介绍
MapReduce的思想核心是“分而治之”,适用于大量复杂的任务处理场景(大规模数据处理场景)。
- Map负责“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。可以进行拆分的
前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。 - Reduce负责“合”,即对map阶段的结果进行全局汇总。
- MapReduce运行在yarn集群:ResourceManager和NodeManager
这两个阶段合起来正是MapReduce思想的体现。
Mapreduce设计思想
MapReduce是一个分布式运算程序的编程框架,核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在Hadoop集群上。
MapReduce设计并提供了统一的计算框架,为程序员隐藏了绝大多数系统层面的处理细节。为程序员提供一个抽象和高层的编程接口和框架。程序员仅需要关心其应用层的具体计算问题,仅需编写少量的处理应用本身计算问题的程序代码。如何具体完成这个并行计算任务所相关的诸多系统层细节被隐藏起来,交给计算框架去处理:
Map和Reduce为程序员提供了一个清晰的操作接口抽象描述。MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现Map和Reduce;MapReduce处理的数据类型
是<key,value>键值对。
- Map:
(k1; v1) -> [(k2; v2)]
- Reduce:
(k2; [v2]) -> [(k3; v3)]
一个完整的MapReduce程序在分布式运行时有三类实例进程:
- AppMaster 负责整个程序的过程调度及状态协调
- MapTask 负责map阶段的整个数据处理流程
- ReduceTask 负责reduce阶段的整个数据处理流程
Mapreduce特点
- 优点
易于编程
可扩展性
高容错性
高吞吐量 - 不适用领域
难以实时计算
不适合流式计算
MapReduce编程流程
Map 阶段 2 个步骤
- 设置 InputFormat 类,将数据切分为 Key-Value(K1和V1) 对,输入到第二步
- 自定义 Map 逻辑,将第一步的结果转换成另外的 Key-Value(K2和V2)对,输出结果
Shuffle 阶段 4 个步骤
- 对输出的 Key-Value 对进行分区
- 对不同分区的数据按照相同的 Key 排序
- (可选) 对分组过的数据初步规约,降低数据的网络拷贝
- 对数据进行分组,相同 Key 的 Value 放入一个集合中
Reduce 阶段 2 个步骤
- 对多个 Map 任务的结果进行排序以及合并, 编写 Reduce 函数实现自己的逻辑,对输入的Key-Value 进行处理,转为新的 Key-Value(K3和V3)输出
- 设置 OutputFormat 处理并保存 Reduce 输出的 Key-Value 数据
以WordCount为例,这个图将阐述整个MapReduce流程:
WordCount实例
需求:在一堆给定的文本文件中统计输出每一个单词出现的总次数
数据格式装备
创建一个新的文件
vi wordcount.txt
向其中放入一下内容并保存
hello,world,hadoop
hive,sqoop,flume,hello
kitty,tom,jerry,world
hadoop
上传到HDFS
hdfs dfs -mkdir /wordcount/
hdfs dfs put wordcount.txt /wordcount
Mapper
以下于JAVA中实现:
public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
String line = value.toString();
String[] split = line.split(",");
for (String word : split) {
context.write(new Text(word), new LongWritable(1));
}
}
}
Reducer
public class WCReducer extends Reducer<Text,LongWritable,Text,LongWritable> {
/**
* 自定义我们的reduce逻辑
* 所有的key都是我们的单词,所有的values都是我们单词出现的次数
*/
@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));
}
}
定义主类,描述Job并提交
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;
//注意以上导包千万不能导错
public class WCDriver {
public static void main(String[] args) throws Exception{
System.setProperty("hadoop.home.dir", "D:\\Hadoop2.6.0");
//建立连接
Configuration cfg = new Configuration();
Job job = Job.getInstance(cfg, "job_wc");
job.setJarByClass(WCDriver.class);
//指定mapper和reducer
job.setMapperClass(WCMapper.class);
job.setReducerClass(WCReducer.class);
//指定mapper输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定partitioner,这里不需要
//job.setNumReduceTasks(4);
//job.setPartitionerClass(WCPartitioner.class);
//指定reducer输出类型
job.setOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//返回执行结果成功与否
boolean result=job.waitForCompletion(true);
System.