MapReduce的简单解释?

与我的CouchDB问题有关。

任何人都可以解释一个麻雀可以理解的MapReduce?

一路下降到Map和Reduce的基础。


地图是一种将某种列表中的项目“转换”为另一种项目并将其放回到同一种列表中的function。

假设我有一个数字列表:[1,2,3],我想每个数字加倍,在这种情况下,“每个数字加倍”的函数是函数x = x * 2。并且没有映射,我可以写一个简单的循环,说

A = [1, 2, 3] foreach (item in A) A[item] = A[item] * 2 

我会有A = [2,4,6],而不是写循环,如果我有一个地图函数,我可以写

 A = [1, 2, 3].Map(x => x * 2) 

x => x * 2是针对[1,2,3]中的元素执行的函数。 会发生什么情况是程序需要每个项目,通过使x等于每个项目来执行(x => x * 2),并产生一个结果列表。

 1 : 1 => 1 * 2 : 2 2 : 2 => 2 * 2 : 4 3 : 3 => 3 * 2 : 6 

所以在用(x => x * 2)执行map函数之后,你会有[2,4,6]。


Reduce是一个“收集”列表中的项目并对它们执行一些计算,从而将它们减less到单个值的函数。

find一个总和或find平均值都是一个reduce函数的实例。 比如如果你有一个数字列表,比如[7,8,9],你想要他们总结,你会写这样一个循环

 A = [7, 8, 9] sum = 0 foreach (item in A) sum = sum + A[item] 

但是,如果您有权限使用reduce函数,则可以这样写

 A = [7, 8, 9] sum = A.reduce( 0, (x, y) => x + y ) 

为什么有两个参数(0和带有x和y的函数)通过​​,现在有点令人困惑。 为了使reduce函数有用,它必须能够获取2个项目,计算某些东西并将这2个项目“减less”为一个单一值,因此程序可以减less每个项目,直到获得单个值。

执行如下:

 result = 0 7 : result = result + 7 = 0 + 7 = 7 8 : result = result + 8 = 7 + 8 = 15 9 : result = result + 9 = 15 + 9 = 24 

但是你不想始终用零开始,所以第一个参数是在那里让你指定一个种子值,特别是第一个result =行中的值。

说你想总结2个列表,它可能看起来像这样:

 A = [7, 8, 9] B = [1, 2, 3] sum = 0 sum = A.reduce( sum, (x, y) => x + y ) sum = B.reduce( sum, (x, y) => x + y ) 

或者更可能在现实世界中find的版本:

 A = [7, 8, 9] B = [1, 2, 3] sum_func = (x, y) => x + y sum = A.reduce( B.reduce( 0, sum_func ), sum_func ) 

它在DB软件中是一件好事,因为通过Map \ Reduce支持,您可以在不需要知道数据库如何存储在数据库中的情况下使用数据库,这就是数据库引擎的用途。

你只需要能够通过提供一个Map或者Reduce函数来“告诉”你想要的引擎,然后DB引擎就可以find数据,应用你的函数,并且得出结果不要你知道它是如何遍历所有的logging。

索引和键,连接和视图以及单个数据库可以容纳的东西很多,所以通过屏蔽数据实际存储的方式,使代码更容易编写和维护。

并行编程也是如此,如果你只是指定你想要的数据,而不是实际的实现循环代码,那么底层的基础架构就可以“并行化”并在并行循环中执行你的函数。

MapReduce是一种并行处理大量数据的方法,不需要开发人员编写除mapper和reduce之外的任何其他代码。

地图function将数据input并输出一个结果,并将其保存在屏障中。 该function可以与大量相同的地图任务并行运行。 然后可以将数据集简化为标量值。

所以如果你把它看作是一个SQL语句

 SELECT SUM(salary) FROM employees WHERE salary > 1000 GROUP by deptname 

我们可以使用地图来获得地图发射到屏障上的薪水大于1000的员工子集。

减less将对每个组进行求和。 给你你的结果集。

只是从我的大学学习笔记中摘取了谷歌纸

  1. 拿一堆数据
  2. 执行某种转换,将每个数据转换为另一种数据
  3. 将这些新数据合并成更简单的数据

第2步是地图。 第3步是减less。

例如,

  1. 在路上的一对压力表上的两个冲动之间获得时间
  2. 将这些时间映射到基于米的距离的速度
  3. 将这些速度降低到平均速度

MapReduce在Map和Reduce之间分割的原因是因为不同的部分可以很容易地并行完成。 (特别是如果Reduce具有某些math特性。)

有关MapReduce的复杂但很好的描述,请参阅: Google的MapReduce编程模型 – 重访(PDF) 。

MAP和REDUCE是从人类杀死最后一只恐龙的时候开始的Lisp函数。

想象一下,你有一个城市的名单,有关名称,住在那里的人数和城市的大小的信息:

 (defparameter *cities* '((a :people 100000 :size 200) (b :people 200000 :size 300) (c :people 150000 :size 210))) 

现在你可能想要find人口密度最高的城市。

首先,我们使用MAP创build城市名称和人口密度列表:

 (map 'list (lambda (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) *cities*) => ((A 500) (B 2000/3) (C 5000/7)) 

现在我们可以使用REDUCEfind人口密度最大的城市。

 (reduce (lambda (ab) (if (> (second a) (second b)) a b)) '((A 500) (B 2000/3) (C 5000/7))) => (C 5000/7) 

组合这两个部分,我们得到下面的代码:

 (reduce (lambda (ab) (if (> (second a) (second b)) a b)) (map 'list (lambda (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) *cities*)) 

我们来介绍一下function:

 (defun density (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) (defun max-density (ab) (if (> (second a) (second b)) a b)) 

然后我们可以写我们的MAP REDUCE代码为:

 (reduce 'max-density (map 'list 'density *cities*)) => (C 5000/7) 

它叫MAPREDUCE (评价是从内到外),所以叫做map reduce

我们以Google文件为例。 MapReduce的目标是能够有效地使用一些类似algorithm的并行处理单元。 例如:你想提取所有的单词和它们在一组文件中的数量。

典型实现:

 for each document for each word in the document get the counter associated to the word for the document increment that counter end for end for 

MapReduce实现:

 Map phase (input: document key, document) for each word in the document emit an event with the word as the key and the value "1" end for Reduce phase (input: key (a word), an iterator going through the emitted values) for each value in the iterator sum up the value in a counter end for 

在这个过程中,您将拥有一个主程序,将“分割”中的文档分割,这些分割将在Map阶段中并行处理。 发出的值由工作人员在专用于工作人员的缓冲区中写入。 主程序接着委托其他工作人员在通知缓冲区已准备好处理时立即执行Reduce阶段。

每个工作者输出(作为Map或Reduce工作者)实际上都是存储在分布式文件系统(Google for GFS)中的文件或用于CouchDB的分布式数据库中的文件。

有关MapReduce的简单快速“傻瓜式”介绍,请访问: http : //www.marcolotz.com/? p = 67

发布一些内容:

首先,为什么最初创buildMapReduce?

基本上谷歌需要一个解决scheme,使大型计算作业容易并行,使数据分布在通过networking连接的多台机器。 除此之外,它必须以透明的方式处理机器故障并pipe理负载平衡问题。

MapReduce的真正优势是什么?

有人可能会说,MapReduce的魔术是基于Map和Reducefunction的应用程序。 我必须承认交配,我坚决不同意。 使MapReduce如此stream行的主要特点是其自动并行化和分布的能力,结合简单的界面。 这些因素与透明的故障处理相结合,大部分的错误使这个框架如此受欢迎。

在纸上多一点深度:

MapReduce最初是在一篇Google论文中提到的(Dean&Ghemawat,2004–链接到这里),作为使用并行方法和商品计算机集群在大数据中进行计算的解决scheme。 与用Java编写的Hadoop相比,Google的框架是用C ++编写的。 该文档描述了一个并行框架如何使用大数据集上函数式编程的Map和Reducefunction。

在这个解决scheme中,将会有两个主要步骤 – 称为Map和Reduce – 在第一个和第二个之间有一个可选的步骤 – 称为Combine。 Map步骤将首先运行,在input键值对中进行计算并生成新的输出键值。 必须记住,input键值对的格式不一定需要与输出格式对匹配。 Reduce步骤将汇集同一个键的所有值,对其执行其他计算。 结果,最后一步将输出键值对。 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)); 

可以注意到,地图读取logging中的所有单词(在这种情况下,logging可以是一行),并将该单词作为关键字发出,数字1作为值发出。 稍后,reduce将分组同一个键的所有值。 举一个例子:假设“房子”这个词在logging中出现了三次。 减速器的input是[house,[1,1,1]]。 在减速器中,它将对关键房屋的所有值进行求和,并给出以下关键值:[house,[3]]。

这是一个如何在MapReduce框架中看起来像的图像:

来自原始MapReduce Google文件的图像

作为MapReduce应用程序的其他经典示例,可以这样说:

•统计URL访问频率

•反向Web链接图

•分布式的Grep

•每个主机的术语向量

为了避免太多的networkingstream量,本文描述了框架应该如何保持数据的局部性。 这意味着它应该总是试图确保运行Map作业的机器在内存/本地存储器中有数据,避免从networking中获取数据。 为了通过放置映射器来减lessnetworking,使用之前描述的可选组合器步骤。 组合器在给定机器上的绘图器的输出上执行计算,然后将其发送到可能在另一台机器上的减速器。

该文件还描述了框架的元素如何在出现故障时的行为。 这篇文章中的这些元素被称为工人和主人。 在开放源代码实现中,它们将被划分为更具体的元素。 由于Google只是在论文中描述了这个方法,而没有发布它的专有软件,所以为了实现这个模型,许多开源框架被创build。 例如,可以说Hadoop或MongoDB中有限的MapReducefunction。

运行时应该处理非专业编程人员的细节,例如分割input数据,在大型机器上安排程序执行,处理机器故障(当然是透明方式),pipe理机器间通信。 经验丰富的用户可能会调整这些参数,因为input数据将如何在工作人员之间进行分区。

关键概念:

容错:它必须适度地容忍机器故障。 为了做到这一点,主人定期对工人进行处理。 如果主人在特定的时间间隔内没有收到给定工人的答复,那么主人会将该工作定义为失败。 在这种情况下,由有故障的工作人员完成的所有地图任务被扔掉,并被分配给另一个可用的工作人员。 如果工作人员仍在处理地图或减less任务,则会发生类似情况。 请注意,如果工作人员已完成其缩减部分,则所有计算在失败时已经完成,不需要重置。 作为失败的主要点,如果主人失败,所有的工作失败。 出于这个原因,可以定义主控制器的定期检查点,以保存其数据结构。 在最后一个检查点和主站故障之间发生的所有计算都将丢失。

局部性:为了避免networkingstream量,框架试图确保所有input数据在本地可用于将要在其上执行计算的机器。 在原始描述中,它使用复制因子设置为3,块大小为64 MB的Google文件系统(GFS)。 这意味着64 MB(即构成文件系统中的一个文件)的相同块将在三台不同的机器上具有相同的副本。 大师知道块在哪里,并尝试在该机器中安排地图作业。 如果失败,主设备将尝试在任务input数据的副本附近分配一台机器(例如,数据机器的同一机架中的工作机)。

任务粒度:假设每个映射阶段被划分为M个片段,并且每个Reduce阶段被划分成R个片断,理想情况是M和R比工作器的数量大得多。 这是因为执行许多不同任务的工作人员改善了dynamic负载平衡。 除此之外,在工作人员失败的情况下,还可以提高恢复速度(因为已完成的许多地图任务可以分散到所有其他机器上)。

备份任务:有时,Map或Reducer工作人员的行为可能比集群中的其他人慢得多。 这可以保持总处理时间并使其等于该单个慢速机器的处理时间。 最初的论文描述了一种备选称为“备份任务”的function,当一个MapReduce操作接近完成时,由主设备进行调度。 这些是正在进行的任务的主人计划的任务。 因此,当主或备份完成时,MapReduce操作完成。

计数器:有时可能希望计数事件的发生。 出于这个原因,计数创build。 每个工人的计数器值会定期传播给主人。 然后,主人聚集(是的,看起来像预聚集合来自这个地方)一个成功的地图的计数器值,减less任务,并返回到用户代码时,MapReduce操作完成。 在主状态下还有一个当前的柜台值,所以观察过程的人可以跟踪它的行为。

那么,我想用上面的所有概念,Hadoop将是你的一块蛋糕。 如果您对原始MapReduce文章或任何相关内容有任何疑问,请告诉我。

这是我find的MapReduce最简单的解释。

在这里输入图像说明

我解释的图片越less,它就越简单。

如果您熟悉Python,以下是对MapReduce最简单的解释:

 In [2]: data = [1, 2, 3, 4, 5, 6] In [3]: mapped_result = map(lambda x: x*2, data) In [4]: mapped_result Out[4]: [2, 4, 6, 8, 10, 12] In [10]: final_result = reduce(lambda x, y: x+y, mapped_result) In [11]: final_result Out[11]: 42 

查看每个原始数据段是如何单独处理的,在这种情况下,乘以2(MapReduce的地图部分)。 基于mapped_result ,我们得出结论是42 (MapReduce的缩减部分)。

这个例子的一个重要结论是,每个处理块都不依赖于另一个块。 例如,如果thread_1映射[1, 2, 3]thread_2映射[4, 5, 6] ,则两个线程的最终结果仍然是[2, 4, 6, 8, 10, 12] thread_2 [4, 5, 6] ,但是我们处理时间缩短了一半 。 对于reduce操作也是如此,并且是MapReduce在并行计算中的工作原理。

我不想听起来陈腐,但是这对我非常有帮助,而且非常简单:

 cat input | map | reduce > output