MapReduce被广泛应用于日志分析、海量数据的排序、在海量数据中查找特定模式等场景中。
一、MapReduce的优势
1、可使用编程语言的多样性:map和reduce程序的编写可用Python/PHP/C++/Java等语言
2、适用性强:可以在任何安装Hadoop集群中运行同样的程序
3、高效性:多台主机一同处理数据。适用于处理大量的数据(这一点有点像是操作系统中程序的并发概念。也可以用多线程的概念来进行理解,为了完成一个任务,启动多个线程来执行提高效率。只不过多线程是通过并行实现,而我们这里属于并发执行)
二、MapReduce的计算模型
(一)、MapReduce Job
1、组成:每个MapReduce任务都被初始化成一个Job,每个Job包括两个阶段:map阶段(对应map函数)和reduce阶段(对应reduce函数)
2、MapReduce的执行过程:
map函数接收一个<key,value>形式的输入,然后同样产生一个<key,value>形式的中间输出。Hadoop负责把具有相同key的<key,value>数据集合到一起传递给reduce函数,reduce函数接收到一个形如<key,(list of values)>形式的输入,然后对这个value集合进行处理,每个reduce产生0个或1个输出,reduce的输出也是<key,value>形式的。MapReduce任务处理的流程如下图。
当我们输入一个任务的时候,它会被划分为多个子任务,送到各个从机上的MapReduce程序进行执行。各个从机执行以后再把它整理起来。
三、Hadoop中的WordCount程序
1、执行过程
首先将文件读取进来,然后交由map程序处理,map将输入读入后,切出其中的单词,并标记它的数目为1,形成<word,1>形式的输出,传送给hadoop。hadoop把具有相同word的<word,1>数据集合起来,形成<word,list of values>的形式。然后传送给reduce,reduce再把<word,list of values>中的1给加起来,输出<word,value>。也就是某个单词出现的次数。最后将这个<key,value>对以TextInputFormat的形式输出到HDFS中。
2、InputFormat()和InputSplit
InputSplit是Hadoop定义的用来传送给每个单独的map的数据,InputSplit的存储并非数据本身,而是一个分片长度和一个记录数据位置的数组。当数据传送给map时,map会将输入分片传送到InputFormat上。InputFormat()方法是用来生成可供map处理的<key,value>键值对的。
TextInputFormat是Hadoop默认的输入方法,在TextInputFormat中,每个文件(或其一部分)都会单独地作为map的输入,而这是继承自FileInputFormat的,之后每行数据都会生成一条记录。每条记录则表示成<key,value>形式。
key值是每个数据的记录在数据分片中的字节偏移量,数据类型是LongWritable;
value值时每行的内容,数据类型是Text;
也就是说数据会以以下的形式输入到map中
file01:
0 hello world bye world
file02:
0 hello hadoop bye hadoop
因为file01和file02都会被单独输入到一个map中,因此它们的key值都是0。也就是在原来文件中的起始位置偏移为0。(这里如果file01文件被划分为不同的数据片分配到不同的map进行处理,那么key就不会都为0。同样,如果把file01和file02合成一个数据片放到同一个map中进行处理,key也不会都是0,但这种情况应该比较少)
2、OutputFormat
默认的输出格式TextOutputFormat。这种输出方式和输入类似,会将每条数据以一行的形式存入文本文件。
在WordCount程序执行结束后,最终的输出如下:
Bye 2
Hadoop 2
Hello 2
World 2
3、map和reduce
map函数:继承自MapReduceBase,并且它实现了Mapper接口,此接口是一个泛型数据。四个参数:分别用来指定输入key值类型、输入value值类型、输出key值类型和输出value值类型。此接口需要实现map方法(负责对输入进行具体操作)。它的输入类型为<LongWritable,Text>,输出类型为<LongWritable,IntWritable>。
在本例中:map方法对输入的行以空格为单位进行切分,然后使用OutputCollect收集输出的<word,1>。
reduce函数:也继承自MapReduceBase,需要实现Reducer接口 ,reduce函数以map的输出作为输入,因此输入类型是<Text,IntWritable>,输出类型也是<Text,IntWritable>。reduce函数需要实现reduce方法,在此方法中,reduce函数将输入的key值作为输出的key值,然后将获得的多个value值加起来,作为输出的value值。
4、运行WordCount程序
这个直接看我的另一篇博客吧,有详细的步骤截图:《在命令行中运行Hadoop自带的WordCount程序》
5、新旧API
Hadoop提供了一个新的API。区别如下:
#新API中,Mapper和Reducer已经不再是一个接口而是抽象类,更容易扩展
#新的API中更广泛地使用了context对象,并使用MapContext进行MapReduce间的通信,MapContext同时充当OutputCollector和Report的角色
#job的配置统一由Configuration来完成,而不必额外地使用JobConf对守护进程进行配置
#由Job类来负责Job的控制,而不是JobClient,JobClient在新的API中已经被删除了。
6、MapReduce的数据流和控制流
6.1.WordCount的执行流程如下图:
#负责控制及调度的MapReduce的job是JobTracker
#TaskTracker负责运行MapReduce的Job
#MapReduce在运行时是分成map task和reduce task来处理的,而不是完整的job。
#简单的控制流:JobTracker调度任务给TaskTracker,TaskTracker执行任务时,会返回进度报告。
6.2.map
map的输出被写入本地磁盘中,不是HDFS上。(较少网络传输)如果map在没来得及将数据传输给reduce就崩溃了,那么JobTracker只需要另选一台机器冲洗执行这个task就可以了
6.3.reduce
reduce会读取map的输出数据,合并value,然后将它们输出到HDFS上。
注意:MapReduce在执行过程中往往不止一个reduce task,reduce task的数量是可以通过程序制定的。当存在多个reduce时,每个reduce都会产生一个输出文件。
另外,没有reduce任务的时候,系统会直接将map的输出结果作为最终结果。有多少个map task就有多少个输出文件。
本篇博文主体内容来自《Hadoop实战》一书。