MapReduce
1 介绍
MapReduce是一个软件框架,基于该框架能够容易地编写应用程序,这些应用程序能够运行在由上千个商用机器组成的大集群上,并以一种可靠的,具有容错能力的方式并行地处理上TB级别的海量数据集。
-
思想:分而治之
-
Mapper负责“分”:
- 即把复杂的任务分解为若干个“简单的任务”来处理
- 一是数据或计算的规模相对原任务要大大缩小
- 二是就近计算原则,即任务会分配到存放着所需数据的节点上进行计算(移动数据不如移动计算)
- 三是这些小任务可以并行计算,彼此间几乎没有依赖关系
- 即把复杂的任务分解为若干个“简单的任务”来处理
-
Reducer负责对map阶段的结果进行汇总
- Reducer个数,可通过在mapred-site.xml配置文件里设置参数mapred.reduce.tasks的值,缺省值为1
-
MapReduce工作机制
# 1.客户端,用来提交MapReduce作业 # 2.JobTracker,用来协调作业的运行 # 3.TaskTracker,用来处理作业划分后的任务 # 4.HDFS,用来在其它实体间共享作业文件
2 架构
-
执行流程:
- 一个MapReduce作业通常会把输入的数据集切分为若干独立的数据块,由Map任务以完全并行的方式去处理它们
- 框架会对Map的输出先进行排序,然后把结果输入给Reduce任务。中间结果会存储在hdfs中,框架负责任务的调度和监控,以及重新执行已经关闭的任务
- MapReduce框架和分布式文件系统是运行在一组相同的节点上,也就是说,计算节点和存储节点通常都是在一起的。可以使得整个集群的网络带宽被非常高效地利用
-
框架组成
-
JobTracker:
负责调度构成一个作业的所有任务,这些任务分布在不同的TaskTracker上
-
TaskTracker
负责执行由JobTracker指派的任务
-
-
输入输出
MapReduce框架运转在<key,value>键值对上,输入输出的键值可能不同。
Client:<k1,v1> --> Map: <k2,v2> --> combine:<k2,v2> --> Reudce:<k3,v3> --> HDFS -
代码演示
package wc1;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import java.io.IOException;
import java.util.StringTokenizer;
public class wordcount {
/**
* @author codingyin
* <p>
* Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
* KEY IN : 行的起始偏移量,原生类型long,对应的Hadoop序列化类型:LongWritable
* VALUE IN:行的文本内容,原生类型String,对应的Hadoop序列化类型:Text
* KEY OUT: 一个单词,原生类型String,对应的Hadoop序列化类型:Text
* VALUE OUT: 单词次数1,原生类型int,对应的Hadoop序列化类型:IntWritable
* String ,Long都是jdk中自带的数据类型,在序列化的时候,效率比较低。hadoop为了提高序列化的效率,他就自己自定义了一套数据结构
* Long------->LongWritable
* String----->Text
* Integer---->IntWritable
* null------->nullWritable
*/
public static class MyMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
/**
* maptask程序在自己的任务范围数据中(数据切片)
* 每读取一行数据,就调一次本map()方法,并将读到的数据以key-value形式作为参数传给本map()方法
* map()方法按照所需的数据处理逻辑对传入的数据进行处理,然后通过context返回给map task程序
*/
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
}
/***
* @author codingyin
* Reduce Task会将自己所收到的key-value数据按照key进行排序和分组,相同key的数据会连续排放在一起,key“较小”的数据排在前面,然后,将key相同的key-value数据作为一组来进行聚合处理;
* Reduce Task对每一组数据处理时,都是调用用户提供的reduce方法,并传入一个key对象和一个迭代器对象给reduce方法来获取这一组数据中的每一个key-value数据;
* 在reduce函数中,我们只需要使用框架所提供的迭代器来迭代reduce task提供的一组key-value数据(具体来说,就是循环反复调用迭代器的next()方法来逐一获取这组数据中的每一对key-value数据);
* 将每次迭代到的value值进行累加,迭代完成之后,累加值即为某一个key(即某个单词)的总词频;
* 将统计出的这个单词及其总词频,通过reduce task所提供的context进行返回。
*/
public static class Myreduce extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
* Reduce Task收集到一组相同key的数据,调一次本方法,比如(a,1)(a,1)(a,1)......(a,1)
*/
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int count = 0;
for (IntWritable val : values) {
count += val.get();
}
context.write(key, new IntWritable(count));
}
}
/**
* @author codingyin
* 入口函数类并且对配置文件进行一些必要的设置
*/
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "word count");
job.setJarByClass(wordcount.class);
// 指定本次job所要用的mapper类和reducer类
job.setMapperClass(MyMapper.class);
job.setCombinerClass(Myreduce.class);
job.setReducerClass(Myreduce.class);
// 指定本次job的mapper类和reducer类输出结果的数据类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
// 指定本次job读取源数据时所需要用的输入组件:源文件在hdfs的文本文件中,用TextInputFormat
job.setInputFormatClass(TextInputFormat.class);
// 指定本次job输出数据时所需要用的输出组件:输出到hdfs文本文件中,用TextOutputFormat
job.setOutputFormatClass(TextOutputFormat.class);
// 指定reduce task运行实例的个数
job.setNumReduceTasks(3);
// 指定源数据文件所在的路径
FileInputFormat.addInputPath(job, new Path(args[1]));
// 指定输出结果数据文件所在的路径
FileOutputFormat.setOutputPath(job, new Path(args[2]));
// 核心代码: 提交jar包给yarn
// job.submit(); // 提交完任务,客户端就退出了
// 提交完任务,客户端打印集群中的运行进度信息,并等待最终运行状态
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}

浙公网安备 33010602011771号