MapReduce的简单解释?
与我的CouchDB问题有关。
谁能用麻木可以理解的术语来解释MapReduce?
解决方案
回答
- 收集大量数据
- 执行某种转换,将每个基准转换为另一种基准
- 将这些新数据合并为更简单的数据
第2步是Map。步骤3是减少。
例如,
- 在道路上的一对压力表上获得两次脉冲之间的时间
- 根据仪表的距离将这些时间映射为速度
- 将这些速度降低到平均速度
MapReduce在Map和Reduce之间划分的原因是因为可以轻松地并行完成不同的部分。 (特别是如果Reduce具有某些数学属性。)
有关MapReduce的复杂但很好的描述,请参阅:Google的MapReduce编程模型-修订(PDF)。
回答
让我们以Google论文为例。 MapReduce的目标是能够有效地使用并行处理某些算法的处理单元的负载。示例如下:我们想提取所有单词及其在一组文档中的计数。
典型的实现:
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为GFS)或者CouchDB的分布式数据库中的文件。
回答
MapReduce是一种并行处理大量数据的方法,无需开发人员编写映射器和reduce函数以外的任何其他代码。
地图功能可将数据输入并取出结果,并将结果保存在障碍中。此功能可以与大量相同的地图任务并行运行。然后可以将数据集缩减为标量值。
因此,如果我们将其视为SQL语句
SELECT SUM(salary) FROM employees WHERE salary > 1000 GROUP by deptname
我们可以使用map来获取薪水> 1000的员工子集
哪个地图将向障碍发射到组大小的存储桶中。
减少将对每个组求和。给我们结果集。
刚刚从我对Google论文的大学学习笔记中摘下来了
回答
一路深入到Map和Reduce的基础知识。
Map是一项功能,可将某种类型的列表中的项目"转换"为另一种类型的项目,并将其放回相同类型的列表中。
假设我有一个数字列表:[1,2,3],我想对每个数字加倍,在这种情况下,"对每个数字加倍"的函数是函数x = x *2. 如果没有映射,我可以编写说一个简单的循环
A = [1, 2, 3] foreach (item in A) A[item] = A[item] * 2
并且我会有A = [2,4,6],但是如果没有map函数,我可以编写而不是编写循环
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是一种"收集"列表中的项目并对所有项目执行一些计算,从而将它们减少为单个值的功能。
求和或者求平均值都是归约函数的所有实例。例如,如果我们有一个数字列表,例如[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 )
现在,为什么要传递2个参数(0和带有x和y的函数)有点令人困惑。为了使reduce函数有用,它必须能够取2个项目,计算出某项并将这2个项目"减少"为一个单一值,因此程序可以将每对减少直到我们拥有一个单一值。
执行如下:
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 )
或者我们更可能在现实世界中找到的版本:
A = [7, 8, 9] B = [1, 2, 3] sum_func = (x, y) => x + y sum = A.reduce( B.reduce( 0, sum_func ), sum_func )
在数据库软件中这是一件好事,因为有了Map \ Reduce支持,我们可以使用数据库而无需知道如何将数据存储在数据库中来使用它,这就是数据库引擎的目的。
我们只需要通过向他们提供Map或者Reduce函数就可以"告诉"我们想要的引擎,然后DB引擎可以找到围绕数据的方式,应用函数,并得出我们想要的结果想要全部,而我们不知道它如何遍历所有记录。
一个数据库可以拥有索引,键,联接和视图以及许多东西,因此通过保护我们免受实际存储数据的方式,使代码的编写和维护变得更加容易。
并行编程也是如此,如果我们仅指定要对数据执行的操作而不是实际实现循环代码,则基础结构可以"并行化"并在同时并行循环中为我们执行功能。
回答
MAP和REDUCE是Lisp的旧功能,源于人类杀死了最后的恐龙。
想象一下,我们有一个城市列表,其中包含有关名称,居住在那里的人数和城市规模的信息:
(defparameter *cities* '((a :people 100000 :size 200) (b :people 200000 :size 300) (c :people 150000 :size 210)))
现在,我们可能想要找到人口密度最高的城市。
首先,我们使用MAP创建城市名称和人口密度的列表:
(map 'list (lambda (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) *cities*) => ((A 500) (B 2000/3) (C 5000/7))
使用REDUCE,我们现在可以找到人口密度最大的城市。
(reduce (lambda (a b) (if (> (second a) (second b)) a b)) '((A 500) (B 2000/3) (C 5000/7))) => (C 5000/7)
结合这两个部分,我们得到以下代码:
(reduce (lambda (a b) (if (> (second a) (second b)) a b)) (map 'list (lambda (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) *cities*))
让我们介绍一下函数:
(defun density (city) (list (first city) (/ (getf (rest city) :people) (getf (rest city) :size)))) (defun max-density (a b) (if (> (second a) (second b)) a b))
然后,我们可以将MAP REDUCE代码编写为:
(reduce 'max-density (map 'list 'density *cities*)) => (C 5000/7)
它称为" MAP"和" REDUCE"(评估由内而外),因此称为" map reduce"。