MapReduce 是一种编程模式,在很大程度上借鉴了函数式语言。它主要的思想是分而治之(divide and conquer)。将一个大的问题切分成很多小的问题,然后在集群中的各个节点上执行,这既是Map过程。在Map过程结束之后,会有一个Ruduce的过程,这个过程即将所有的Map阶段产出的结果进行汇集。
上述过程可以说是一个显而易见的过程,所以说MapReduce 是一个极其简单而有极其复杂的编程模式。说它简单是因为在程序员使用它编程解决实际问题时,他只要编写一个Mapper 函数和一个Reduce 函数,或许在复杂一点加上一个Combiner 函数和Partitioner 函数,其余的就直接交给MapReduce框架执行。这样程序员就只要关注数据业务,而不用关注具体的执行过程。但说它复杂是因为MapRuduce 有着看不见的部分,在程序员准备好Mapper 和Reducer 之后提交个MapReduce,而具体执行过程却是一个非常复杂的过程。
MapReduce在具体执行过程中,同步化是一个非常棘手的问题。在MapReduce的并行执行过程唯一发生集群级同步化是在 Shuffle 和Sort阶段,即在Mapper阶段完成后,将各个节点上的中间结果Key/Value 依据Key的值聚集后复制到Reducer节点上。除此之外的过程,各个节点都是独立运行的而且没有直接的通信。这就意味着程序员对MapReduce的执行过程的很多方面都没有控制能力,比如:
- 集群中哪个节点来执行Mapper 和Reducer 。
- 什么时候开始和结束Mapper 和Reducer。
- 输入的key/value 由哪个Mapper 来处理。
- 中间结果产生的key/value 由哪个Reucer来处理。
所谓山不转水转,从另一个角度来说,程序员可以控制以下的几个方面:
- 数据结构的自定义,即key/value的具体的结构可以是程序员自定义的。
- MapReude 每个Mapper 和Reducer 的执行过程在开始和结束都可以有一段程序自定义代码,来确定每个Mapper 和Reducer 在执行之前和结束后的动作。比如Hadoop在实现MapReude框架时,每个Mapper 和Reducer 都有一个setup 和cleanup 函数,既是定义开始和结束的动作。在一些MapReduce优化算法中会充分利用这两个函数。
- 对MapRuduce的Mapper 的输入Key 和Reducer 的中间结果Key 状态的控制。
- 对中间结果Key 排序的控制,这样程序员就有能力控制Reducer 处理Key的顺序。
- 对中间结果Key 分区的控制,这样程序员就有能力控制Reducer 处理Key的集合。
虽然说MapRudce 框架为我们提供了良好的编程模式和接口,但是从上面的可控方面和不可控方面,我们可以挖掘出一些有效的设计模式。这些模式或可以帮助我们提高MapReduce 的执行效率,或可以帮助我们更好的控制代码执行和数据流模式转化。下面具体介绍MapReduce 算法设计。
1. 本地聚集
在偏数据敏感的分布式处理中,一个重要的性能瓶颈是中间结果的网络传输。就拿Hadoop来说,它将Mapper 处理的中间结果在本地磁盘上存储(该过程还涉及到序列化),然后通过网络传输给Reducer。这里磁盘和网络的延时会极大的影响MapReduce 的执行效率。很容易想到的解决方案就是如何减少中间结果的大小来提高效率。而本地聚集(local aggregation)可以减少中间结果的产生,从而能提高MapReduce 的效率(特别是对于一个Mapper 可能产生多个相同的Key)。
1.1 Combiner 和 in-Mapper Combining
Combiner 在大多数MapReduce 实现中都会提供的,它的主要作用是对每个Mapper产生的结果进行本地聚集。我们知道在MapReducer 的输入实现过程是大致这样的:一个大的作业文件会通过MapReduce提供的Splitter 来进行切割成多个小的文件,每个文件会被一个Mapper处理,而每个小文件又会被MapReduce提供的RecordReader进行分割形成很多的key/value 形式的记录,每个Mapper对象中的map 方法会对每条key/value 的记录进行处理。处理后会形成一个新的Key/value 的中间结果,会序列化写到本地磁盘。
举个常见的例子来说:数单词。假设现在有100 篇的文集,要数出每个单词出现的次数。MapRudce 接到这个任务后,首先检测文集数据的正确性。然后进行分割(这里我们采用逻辑上的分割)。比如集群有10 个TaskTracker可用。MapReduce 将100文档进行平均分割,每个TaskTracker会得到10篇文集。若每个TaskTracker运行一个Mapper的话,这10篇文集会一次被Mapper 处理。10篇文集又会被分切成10个RecordReader形式的Key/Value(key=docId,value=docContent)。这样一个Mapper 一次就会处理一片文档。具体算法伪码如下:
1: class Mapper
2: method Map(docid a; doc d)
3: for all term t in doc d do
4: Emit(term t; count 1)
1: class Reducer
2: method Reduce(term t; counts [c1; c2; : : :])
3: sum = 0
4: for all count c in counts [c1; c2; : : :] do
5: sum = sum + c
6: Emit(term t; count sum)
|
首先,我们来讨论Combiner的使用。上述算法只使用了Mapper 和Reducer ,并没有使用Combiner ,这个算法的中间结果都是(term t; count 1) 的形式。即每个单词记录一次,这样的中间结果会很多。我们在下面改进的算法中使用Combiner 。
1: class Mapper
2: method Map(docid a; doc d)
3: H = new AssociativeArray
4: for all term t in doc d do
5: H{t} = H{t} + 1 . //Tally counts for entire document
6: for all term t in H do
7: Emit(term t; count H{t})
1: class Reducer
2: method Reduce(term t; counts [c1; c2; : : :])
3: sum = 0
4: for all count c in counts [c1; c2; : : :] do
5: sum = sum + c
6: Emit(term t; count sum)
|
从改进算法的伪码中我们可以看出,我们只是在Mapper中的map方法中添加一个关联数组(即JAVA中的Map)。每次map 处理一个文档时,并不是遇到一个单词就写到本地磁盘,而是将其添加到关联数组中,并且关联数组的值加1。在所有单词处理完后,在使用一个for循环将所有的单词及其出现在该文档中的次数写回本地磁盘。这样每个Mapper 的输出就是一个Map方法处理一篇文集中的单词及其出现在该文档中的次数。比如在处理docId =“16”的时候,单词“link”在这个文集中出现了5次。在没有使用Combiner的情况下,会有5个中间结果写回磁盘即(link;1), (link;1), (link;1), (link;1), (link;1)。而在使用Combiner 的情况下对于单词“link”只会有一个中间结果(link;5)写回磁盘。从中可以看出Combiner可以减少中间结果的数量。
这个的Combiner只是对本地Map方法产生的结果进行汇总。其作用相当于一个“mini-Reducer”。而事实上在Hadoop的MapReduce的实现中,其Combiner就是实现一个Reducer。
上述的算法相比没有Combiner 的算法有了很大的提高,实际上该算法还有提升的空间。这就是接下来要讲的“In-Mapper Combining”。
Combiner 的使用可以使得每个Mapper 的map 方法产生的结果本地聚集。实际上更为有效是,我们可以让每个Mapper 的结果本地聚集。上面数单词的例子中,每个Mapper 会处理10 文档,而Mapper中的map方法会每次处理1个文档,map会循环10遍。我们可以直接将 10个文档的单词进行本地聚集。
下面是使用 “In-Mapper Combining”的算法伪码实现:
1: class Mapper
2: method Initialize
3: H = new AssociativeArray
4: method Map(docid a; doc d)
5: for all term t in doc d do
6: H{t} = H{t} + 1 . //Tally counts across documents
7: method Close
8: for all term t in H do
9: Emit(term t; count H{t})
1: class Reducer
2: method Reduce(term t; counts [c1; c2; : : :])
3: sum = 0
4: for all count c in counts [c1; c2; : : :] do
5: sum = sum + c
6: Emit(term t; count sum)
|
从上面使用“In-Mapper Combining”的伪码中可以看出,Mapper中的不只是有map 一个方法,而是增加了Initialize 和Close 方法。即我们之前说的每个Mapper执行过程中在开始和结束都可以有一段程序自定义代码,来确定每个Mapper 和Reducer 在执行之前和结束后的动作。这里对应Hadoop 中的方法是:setup 和 cleanup 方法。
下面对该算法分析:在每个Mapper 启动的时候会有一个关联数组的产生。在执行每个Map方法执行完时,并不直接写回磁盘,而是将单词加入到关联数组中,在整个Mapper执行完后才将所有单词写回磁盘(Close方法完成)。对应数单词的例子来说,每个Mapper不是在每篇文档处理完后写回磁盘的,而是每个Spiltter 的10篇文档处理完后,才一次性写回磁盘。这样中间结果相比直接使用Combiner就更少。
1.2 Combiner 和 in-Mapper Combining的优缺点
In-Mapper Combining 虽然比Combiner 有更少的中间结果。但是它有几个缺点。首先它破坏了MapReduce 编程模式的基础,因为保存中间结果跨越了多个Key/Value。如果说为了效率,我们不刻意的去追求模式。但是对于一些特定的算法它是不合适使用,比如某些算法要求对Map方法处理的Key/Value的中间结果先后有要求,那么这种In-Mapper Combining 是不适应的。另一个重要的缺点是In-Mapper Combining 对拓展性提出了挑战。以数单词为例,假设Mapper处理的10篇文档很大设计到很多的单词,这样关联数组势必会非常大,又可能大到一个JVM不能完全存储这个关联数组。这样拓展性会遇到挑战。
对于第二个缺点,我可以采用定期写回磁盘的方法来解决。
Combiner 和In-Mapper Combining 有除了减少中间结果外,还可以减小分布的倾斜度。比如在数单词的例子中,一些常用的单词,可能会有很多的中间结果,以至于处理这些常用单词的Reducer 会比其他的Reducer 慢很多,这种Reducer拖后腿的现象在MapReducer经常出现,而Combiner 和In-Mapper Combining的使用有助于减少这种情况。
分享到:
相关推荐
Ch6-MapReduce算法设计.ppt.ppt
MapReduce是一种分布式计算框架,由Google开发,用于处理和生成大型数据集。它将复杂的计算任务分解为两个主要阶段:...因此,随着数据量的增长,MapReduce及其相关的算法设计成为了解决大规模数据处理问题的关键工具。
2. **MapReduce算法设计**: - **特征选择算法**:邮件分类的第一步是特征选择,这涉及从原始邮件文本中提取有意义的关键词,以表征邮件的主题。这个过程通常会去除停用词,比如数字、标点符号等无关词汇。 - **...
内容概要:本文深入讲解了Hadoop及其生态系统,重点介绍了MapReduce算法的工作原理、编程模型、数据流与分区。通过实例详细解析了如何使用MapReduce实现经典的大数据处理任务,如Word Count、矩阵乘法和PageRank算法...
6. 决策树算法在MapReduce中的实现细节:在基于MapReduce实现决策树算法中,需要对决策树算法的实现细节进行详细的设计和实现,例如对树的节点进行实现、对决策树的分裂和叶节点的计算等。 7. MapReduce框架在决策...
项目的具体内容如下:1:用MapReduce算法实现贝叶斯分类器的训练过程,并输出训练模型; 2:用输出的模型对测试集文档进行分类测试。测试过程可基于单机Java程序,也可以是MapReduce程序。输出每个测试文档的分类...
2. MapReduce算法设计:详细阐述了算法设计的各个重要方面,比如局部聚合(Local Aggregation)、键值对的处理(Pairs and Stripes)、相对频率的计算(Computing Relative Frequencies)、次级排序(Secondary ...
- **第3章:MapReduce算法设计** 探讨了如何设计有效的MapReduce算法,包括局部聚合、配对与条纹化、相对频率计算、二次排序、关系连接等技术。 - **第4章:用于文本检索的倒排索引** 讨论了如何构建和优化倒排...
### MapReduce算法设计 #### 本地聚合 本地聚合是MapReduce中优化性能的关键技术之一,通过在Mapper阶段进行局部汇总,减少Shuffle阶段的数据传输量。Combiners和In-Mapper Combining是实现本地聚合的两种方式,...
学习MapReduce不仅需要理解其基本概念,还要掌握如何设计和优化Map和Reduce函数,以及如何处理数据分片和分区策略。通过深入学习和实践,可以更好地利用云计算平台提供的MapReduce服务,有效处理和分析大规模数据。
因此,《使用MapReduce进行数据密集型文本处理》一书不仅提供了一个关于MapReduce算法设计的全面概览,还结合了自然语言处理、信息检索和机器学习中常见的文本处理算法,使得读者能够深入理解如何在大规模数据处理...
#### 三、MapReduce算法设计 MapReduce算法的设计涉及到多种技术,包括但不限于局部聚合、对和条纹、相对频率计算、二次排序、关系连接等。 - **局部聚合**:通过在Mapper端使用Combiners来减少Reduce端的通信开销...
本话题将深入探讨如何使用Hadoop MapReduce实现两个矩阵相乘的算法,这在数据分析、机器学习以及高性能计算中有着重要应用。 首先,理解矩阵相乘的基本原理至关重要。矩阵相乘不是简单的元素对元素相乘,而是对应...
MapReduce设计模式是对MapReduce编程范式的进一步深化,通过多种不同的算法和策略来解决数据处理中的常见问题。 本文档中提到了《MapReduce设计模式》这本书,由Donald Miner和Adam Shook所著。书籍的标题说明了其...
#### MapReduce算法设计 - **Map 阶段**:在这个阶段,每个文档被处理成键值对的形式,键通常是文档ID或文档标识符,而值则包含文档的内容或词权重向量。MapReduce框架会将这些键值对分发到不同的处理节点进行并行...
#### 三、MapReduce算法设计 对于题目中提到的问题,我们可以设计一个基于MapReduce的解决方案来寻找有向图中的所有三角形。 **1. 输入数据格式** 输入数据以键值对的形式表示每条边:<(源节点, 目标节点), 无>。...