Map reduce 是一个为高效处理大量数据而开发的框架。
例如,如果我们在一个数据集中有 100 万条记录,并且它以关系表示形式存储 - 派生值并对这些值执行任何类型的转换都是非常昂贵的。
例如在 SQL 中,给定出生日期,找出有多少人的年龄 > 30 岁的一百万条记录将需要一段时间,而且当查询的复杂性增加时,这只会按数量级增加.
Map Reduce 提供基于集群的实现,其中数据以分布式方式处理
寻找朋友
MapReduce 是最初由 Google 开发的框架,它允许
用于跨多个域的轻松大规模分布式计算。
Apache Hadoop 是一个开源实现。
我将掩盖细节,但归结为定义两个
函数:一个map函数和一个reduce函数。地图功能
接受一个值并输出键:值对。例如,如果我们定义
一个 map 函数,它接受一个字符串并输出单词的长度
作为键和单词本身作为值然后 map(steve) 将
返回 5:steve 和 map(savannah) 将返回 8:savannah。你可能有
注意到 map 函数是无状态的,只需要输入
value 来计算它的输出值。这允许我们运行地图
并行地对值起作用,并提供了巨大的优势。
在我们进入reduce函数之前,mapreduce框架组
通过键将所有值组合在一起,因此如果映射函数输出
以下键:值对:
3 : the
3 : and
3 : you
4 : then
4 : what
4 : when
5 : steve
5 : where
8 : savannah
8 : research
它们被分组为:
3 : [the, and, you]
4 : [then, what, when]
5 : [steve, where]
8 : [savannah, research]
然后这些行中的每一行都将作为参数传递给 reduce
函数,它接受一个键和一个值列表。在这种情况下,
我们可能试图弄清楚有多少特定长度的单词
存在,所以我们的reduce函数只会计算项目的数量
列表并输出具有列表大小的键,例如:
3 : 3
4 : 3
5 : 2
8 : 2
减少也可以并行完成,再次提供巨大的
优势。然后我们可以查看这些最终结果并看到
在我们的语料库中只有两个长度为 5 的单词,等等......
mapreduce 最常见的例子是计算
词在语料库中出现的次数。假设你有一份互联网副本
(我很幸运能够在这种情况下工作),并且
你想要一个互联网上每个单词的列表以及有多少
它发生的次数。
您处理此问题的方法是将您的文档标记化
拥有(将其分解为单词),并将每个单词传递给映射器。映射器
然后会将单词连同1 的值一起吐出。这
分组阶段将获取所有键(在本例中为单词),并制作一个
1 的列表。然后,reduce 阶段需要一个键(单词)和一个列表
(每次密钥出现在互联网上时的 1 列表),以及
总结列表。然后 reducer 输出这个词,连同它的
数数。当一切都说完了,你会得到一个每个单词的列表
互联网,以及它出现的次数。
很简单,对吧?如果你曾经读过 mapreduce,上面的场景
不是什么新东西……它是 mapreduce 的“Hello, World”。所以这里是
一个真实世界的用例(Facebook 可能会也可能不会真正做到
以下,只是一个例子):
Facebook 有一个朋友列表(请注意,朋友是双向的
脸书上的事。如果我是你的朋友,你就是我的)。他们还有
大量磁盘空间,它们服务于数亿个请求
每天。他们决定在可能的情况下预先计算
减少请求的处理时间。一种常见的处理请求
是“你和乔有 230 个共同的朋友”功能。当你
访问某人的个人资料,您会看到您拥有的朋友列表
常见的。此列表不会经常更改,因此很浪费
每次访问配置文件时重新计算它(确保您可以使用
一个不错的缓存策略,但是我将无法继续
为这个问题写关于 mapreduce 的文章)。我们将使用
mapreduce 这样我们就可以计算出每个人的共同朋友一次
天并存储这些结果。稍后它只是一个快速查找。我们已经
有很多磁盘,很便宜。
假设好友存储为 Person->[List of Friends],我们的
那么朋友列表是:
A -> B C D
B -> A C D E
C -> A B D E
D -> A B C E
E -> B C D
每一行都是映射器的一个参数。送给身边的每一位朋友
好友列表,映射器会输出一个键值对。关键将
与此人成为朋友。该值将是列表
朋友们。键将被排序,以便朋友按顺序排列,
导致所有成对的朋友都去同一个减速器。这很难
用文字解释,所以让我们这样做,看看你是否能看到
图案。在所有映射器运行完毕后,您将拥有一个列表
像这样:
For map(A -> B C D) :
(A B) -> B C D
(A C) -> B C D
(A D) -> B C D
For map(B -> A C D E) : (Note that A comes before B in the key)
(A B) -> A C D E
(B C) -> A C D E
(B D) -> A C D E
(B E) -> A C D E
For map(C -> A B D E) :
(A C) -> A B D E
(B C) -> A B D E
(C D) -> A B D E
(C E) -> A B D E
For map(D -> A B C E) :
(A D) -> A B C E
(B D) -> A B C E
(C D) -> A B C E
(D E) -> A B C E
And finally for map(E -> B C D):
(B E) -> B C D
(C E) -> B C D
(D E) -> B C D
Before we send these key-value pairs to the reducers, we group them by their keys and get:
(A B) -> (A C D E) (B C D)
(A C) -> (A B D E) (B C D)
(A D) -> (A B C E) (B C D)
(B C) -> (A B D E) (A C D E)
(B D) -> (A B C E) (A C D E)
(B E) -> (A C D E) (B C D)
(C D) -> (A B C E) (A B D E)
(C E) -> (A B D E) (B C D)
(D E) -> (A B C E) (B C D)
每一行都将作为参数传递给reducer。减少
函数将简单地与值列表相交并输出相同的值
键与交集的结果。例如,reduce((A B) ->
(A C D E) (B C D)) 将输出 (A B) : (C D) 表示朋友 A
和 B 有 C 和 D 作为共同的朋友。
还原后的结果是:
(A B) -> (C D)
(A C) -> (B D)
(A D) -> (B C)
(B C) -> (A D E)
(B D) -> (A C E)
(B E) -> (C D)
(C D) -> (A B E)
(C E) -> (B D)
(D E) -> (B C)
现在当 D 访问 B 的个人资料时,我们可以快速查找 (B D) 并查看
他们有三个共同的朋友,(A C E)。