1映射和化简编辑
简单说来,一个映射函数就是对一些独立元素组成的概念上的列表(例如,一个测试成绩的列表)的每个元素进行指定的操做(好比前面的例子里,有人发现全部学生的成绩都被高估了一分,他能够定义一个“减一”的映射函数,用来修正这个错误。)。事实上,每一个元素都是被独立操做的,而原始列表没有被更
改,由于这里建立了一个新的列表来保存新的答案。这就是说,Map操做是能够高度并行的,这对高性能要求的应用以及
并行计算领域的需求很是有用。
而化简操做指的是对一个列表的元素进行适当的合并(继续看前面的例子,若是有人想知道班级的平均分该怎么作?他能够定义一个化简函数,经过让列表中的元素跟本身的相邻的元素相加的方式把列表减半,如此
递归运算直到列表只剩下一个元素,而后用这个元素除以人数,就获得了平均分。)。虽然他不如映射函数那么并行,可是由于化简老是有一个简单的答案,大规模的运算相对独立,因此化简函数在高度并行环境下也颇有用。[1]
2分布可靠编辑
MapReduce经过把对数据集的大规模操做分发给网络上的每一个节点实现可靠性;每一个节点会周期性的返回它所完成的工做和最新的状态。若是一个节点保持沉默超过一个预设的时间间隔,主节点(类同Google File System中的主服务器)记录下这个节点状态为死亡,并把分配给这个节点的数据发到别的节点。每一个操做使用命名文件的
原子操做以确保不会发生并行线程间的冲突;当文件被更名的时候,系统可能会把他们复制到任务名之外的另外一个名字上去。(避免反作用)。
化简操做工做方式与之相似,可是因为化简操做的可并行性相对较差,主
节点会尽可能把化简操做只分配在一个节点上,或者离须要操做的数据尽量近的节点上;这个特性能够知足Google的需求,由于他们有足够的带宽,他们的内部网络没有那么多的机器。[1]
3用途编辑
在Google,MapReduce用在很是普遍的
应用程序中,包括“分布grep,分布排序,web链接图反转,每台机器的词矢量,web访问日志分析,反向索引构建,文档聚类,机器学习,基于统计的机器翻译...”值得注意的是,MapReduce实现之后,它被用来从新生成Google的整个索引,并取代老的ad hoc程序去更新索引。
MapReduce会生成大量的
临时文件,为了提升效率,它利用Google文件系统来管理和访问这些文件。
在谷歌,超过一万个不一样的项目已经采用MapReduce来实现,包括大规模的算法图形处理、文字处理、数据挖掘、机器学习、统计机器翻译以及众多其余领域。
其余实现
Nutch项目开发了一个实验性的MapReduce的实现,也便是后来大名鼎鼎的
hadoop
Yonghong Z-Data Mart是由北京永洪科技基于MapReduce原理实现的一款热内存计算的数据集市。
4统计词频编辑
方法一:我能够写一个小程序,把全部论文按顺序遍历一遍,统计每个遇到的单词的出现次数,最后就能够知道哪几个单词最热门了。
这种方法在数据集比较小时,是很是有效的,并且实现最简单,用来解决这个问题很合适。
方法二:写一个多线程程序,并发遍历论文。
这个问题理论上是能够高度并发的,由于统计一个文件时不会影响统计另外一个文件。当咱们的机器是多核或者多处理器,方法二确定比方法一高效。可是写一个多线程程序要比方法一困难多了,咱们必须本身同步共享数据,好比要防止两个线程重复统计文件。
方法三:把做业交给多个计算机去完成。
咱们可使用方法一的程序,部署到N台机器上去,而后把论文集分红N份,一台机器跑一个做业。这个方法跑得足够快,可是部署起来很麻烦,咱们要人工把程序copy到别的机器,要人工把论文集分开,最痛苦的是还要把N个运行结果进行整合(固然咱们也能够再写一个程序)。
方法四:让MapReduce来帮帮咱们吧!
MapReduce本质上就是方法三,可是如何拆分文件集,如何copy程序,如何整合结果这些都是框架定义好的。咱们只要定义好这个任务(
用户程序),其它都交给MapReduce。
map函数
map函数和reduce函数是交给用户实现的,这两个函数定义了任务自己。
map函数:接受一个键值对(key-value pair),产生一组中间键值对。MapReduce框架会将map函数产生的中间键值对里键相同的值传递给一个reduce函数。
reduce函数:接受一个键,以及相关的一组值,将这组值进行合并产生一组规模更小的值(一般只有一个或零个值)。
统计词频的MapReduce函数的核心代码很是简短,主要就是实现这两个函数[参考自MapReduce: ]。
map(String key, String value):
// key: document name
// value: document contents
for each word w in value:
EmitIntermediate(w, "1");
reduce(String key, Iterator values):
// key: a word
// values: a list of counts
int result = 0;
for each v in values:
result += ParseInt(v);
Emit(AsString(result));
在统计词频的例子里,map函数接受的键是文件名,值是文件的内容,map逐个遍历单词,每遇到一个单词w,就产生一个中间键值对<w, "1">,这表示单词w咱又找到了一个;MapReduce将键相同(都是单词w)的键值对传给reduce函数,这样reduce函数接受的键就是单词w,值是一串"1"(最基本的实现是这样,但能够优化),个数等于键为w的键值对的个数,而后将这些“1”累加就获得单词w的出现次数。最后这些单词的出现次数会被写到用户定义的位置,存储在底层的
分布式存储系统(GFS或HDFS)。
工做原理
右图是论文里给出的流程图。一切都是从最上方的user program开始的,user program连接了MapReduce库,实现了最基本的Map函数和Reduce函数。图中执行的顺序都用数字标记了。
1.MapReduce库先把user program的输入文件划分为M份(M为用户定义),每一份一般有16MB到64MB,如图左方所示分红了split0~4;而后使用fork将用户进程拷贝到集群内其它机器上。
2.user program的副本中有一个称为master,其他称为worker,master是负责调度的,为空闲worker分配做业(Map做业或者Reduce做业),worker的数量也是能够由用户指定的。
3.被分配了Map做业的worker,开始读取对应分片的输入数据,Map做业数量是由M决定的,和split一一对应;Map做业从输入数据中抽取出键值对,每个键值对都做为
参数传递给map函数,map函数产生的中间键值对被
缓存在内存中。
4.缓存的中间键值对会被按期写入
本地磁盘,并且被分为R个区,R的大小是由用户定义的,未来每一个区会对应一个Reduce做业;这些中间键值对的位置会被通报给master,master负责将信息转发给Reduce worker。
5.master通知分配了Reduce做业的worker它负责的分区在什么位置(确定不止一个地方,每一个Map做业产生的中间键值对均可能映射到全部R个不一样分区),当Reduce worker把全部它负责的中间键值对都读过来后,先对它们进行排序,使得相同键的键值对汇集在一块儿。由于不一样的键可能会映射到同一个分区也就是同一个Reduce做业(谁让分区少呢),因此排序是必须的。
6.reduce worker遍历排序后的中间键值对,对于每一个惟一的键,都将键与关联的值传递给reduce函数,reduce函数产生的输出会添加到这个分区的输出文件中。
7.当全部的Map和Reduce做业都完成了,master唤醒正版的user program,MapReduce
函数调用返回user program的代码。
全部执行完毕后,MapReduce输出放在了R个分区的输出文件中(分别对应一个Reduce做业)。用户一般并不须要合并这R个文件,而是将其做为输入交给另外一个MapReduce程序处理。整个过程当中,输入数据是来自底层
分布式文件系统(GFS)的,中间数据是放在本地文件系统的,最终输出数据是写入底层分布式文件系统(GFS)的。并且咱们要注意Map/Reduce做业和map/reduce函数的区别:Map做业处理一个输入数据的分片,可能须要调用屡次map函数来处理每一个输入键值对;Reduce做业处理一个分区的中间键值对,期间要对每一个不一样的键调用一次reduce函数,Reduce做业最终也对应一个输出文件。
5思想来源编辑
Hadoop的思想来源于Google的几篇论文,Google的那篇MapReduce论文里说:Our abstraction is inspired by the map and reduce primitives present in Lisp and many other functional languages。这句话提到了MapReduce思想的渊源,大体意思是,MapReduce的灵感来源于函数式语言(好比Lisp)中的内置函数map和reduce。函数式语言也算是阳春白雪了,离咱们普通开发者老是很远。简单来讲,在函数式语言里,map表示对一个列表(List)中的每一个元素作计算,reduce表示对一个列表中的每一个元素作迭代计算。它们具体的计算是经过传入的函数来实现的,map和reduce提供的是计算的框架。不过从这样的解释到现实中的MapReduce还太远,仍然须要一个跳跃。再仔细看,reduce既然能作迭代计算,那就表示列表中的元素是相关的,好比我想对列表中的全部元素作相加求和,那么列表中至少都应该是数值吧。而map是对列表中每一个元素作单独处理的,这表示列表中能够是杂乱无章的数据。这样看来,就有点联系了。在MapReduce里,Map处理的是原始数据,天然是杂乱无章的,每条数据之间互相没有关系;到了Reduce阶段,数据是以key后面跟着若干个value来组织的,这些value有相关性,至少它们都在一个key下面,因而就符合函数式语言里map和reduce的基本思想了。[3]
这样咱们就能够把MapReduce理解为,把一堆杂乱无章的数据按照某种特征概括起来,而后处理并获得最后的结果。Map面对的是杂乱无章的互不相关的数据,它解析每一个数据,从中提取出key和value,也就是提取了数据的特征。通过MapReduce的Shuffle阶段以后,在Reduce阶段看到的都是已经概括好的数据了,在此基础上咱们能够作进一步的处理以便获得结果。这就回到了最初,终于知道MapReduce为什么要这样设计。