
1.4 map和reduce编程风格
与标准的线性编程工作流相比,并行编程工作流有以下3个不同点:
1. 把工作分成多块。
2. 分别处理这些块。
3. 重新组装。
在本书中,我们将用map和reduce函数来处理这3个部分。
1.4.1 用来转换数据的map函数
map是一个用来将数据序列从一种类型转换为另一种类型的函数(如图1.4所示)。这个函数的名字来源于数学。在数学中,一些数学家把函数看作接受一个输入并返回相应输出的一组规则。再次考虑一下那些年轻而有抱负的程序员,他们可能希望将一组Web页面(或者所有的Web页面)映射(map)为这些页面所包含的URL。然后,他们可以使用这些URL来查看哪些页面被链接得最多,以及被哪个页面链接得最多。

图1.4 我们可以使用map函数将数据序列从一种类型转换为另一种类型,例如将Web页面的URL转换为这些页面上的链接列表。
关于map函数要记住的一个关键点是,它会始终在输出中保留与输入中数量相同的对象。例如,如果我们希望使用map函数获得100000个站点上的出站链接,那么结果的数据结构将是100000个链接列表。
注意 map和reduce起源于一种名为声明式编程的编程风格。声明式编程的重点是解释代码的逻辑,而不是具体的底层细节。这就是为什么通过map和reduce风格来扩展代码是很自然的:逻辑保持不变,只是问题的大小发生了变化。
现在,我们有必要看一看应用map函数的一个小例子,因为它对本书中即将要做的事情非常重要。想象一下,我们想要在一个含有4个数字的序列(-1、0、1和2)上加上7。为此,我们编写了一个名为add_seven的小函数,它接受一个数字n并返回n+7。为了对该数字序列执行该操作,我们只需要对add_seven和数字序列调用map函数(如图1.5所示)。
你会注意到,就像我们之前提到的,这里有相同数量的输入(4个)和输出(4个)。而且,这些输入和输出有直接的1对1关系:输出中的每一项对应着输入中的每一项。

图1.5 map函数的一个基本用法是让一个数字序列的每一项依次增加,比如将-1、0、1和2更改为6、7、8、9。
1.4.2 用于高级转换的reduce函数
如果我们想把这个序列变成另一个长度的序列,就需要使用另一个关键函数:reduce。reduce函数允许我们将一个数据序列转换成任何形状或者大小的数据结构(如图1.6所示)。例如,如果我们的程序员想要获取网页链接并将它们转换为频率统计——为了查找哪个页面被链接的次数最多,那么他们就需要使用reduce函数,因为被链接的页面数量可能与抓取的页面数量不同。我们可以很容易地想象到,100个Web页面可能会链接到0到100万个外部页面,这取决于抓取的Web页面是什么。

图1.6 我们可以使用reduce函数将一种类型的数据序列转换成另一种类型的数据序列,甚至转换成某个基本类型的数据。
如果愿意,我们甚至可以使用reduce函数将数据序列转换为基本的数据类型,比如整数或者字符串。例如,我们可以使用reduce函数来计算100个Web页面上的出站链接的数量(一个整数),或者我们可以使用它来查找某段长文本文档中最长的单词,比如一本书(一个字符串)。在这种情况下,reduce函数要比map函数灵活得多。
1.4.3 用于数据转译管道的map和reduce函数
通常,我们在使用map和reduce函数时,会先使用map函数,再使用re-duce函数。这种模式产生了MapReduce编程模式。MapReduce编程模式依赖于map函数来将一些数据转换成另一种类型的数据,然后使用reduce函数组合这些数据。在某次数学考试中,可能有道题是对一串数字的最大质因数求和。我们可以使用map函数将每个数字转换成它最大的质因数,然后使用reduce函数计算它们的和。一个更实际的例子可能是在一组网页(Web页面)中找到最长的单词,而我们有的只是网页的URL。我们可以使用map函数将URL转换为文本,并使用reduce函数来查找最长的单词(如图1.7所示)。

图1.7 map和reduce函数经常一起被用来快速地执行大量数据的复杂转换。