



在2.3.1节中我们讨论了使用Spark编程与使用普通C++/Java/Python语言编写数据处理程序的不同。这里我们想进一步讨论一下大数据编程模型的演变过程。2014年Google发表了 MapReduce 论文,将大数据的编程模型抽象为map和reduce阶段,核心是map()和reduce()函数,通过组合这两个函数可以完成一大部分的数据处理任务(主要是可以被分治处理的粗粒度任务)。对于用户来说,给定一个数据处理任务,需要解决的问题就是如何设计这两个函数来实现任务。这样的好处是用户并不需要关心系统是怎么分布运行的,而坏处是用户需要按照固定的map—reduce计算流程去设计。对于一个复杂的数据处理流程,也就是一个workflow,用简单的map()/reduce()函数去实现这个workflow会很困难。例如,需要自己设计生成多少个job,每个job只包含map()函数,还是map()和reduce()函数都包含,job之间的数据如何存放、连接等。再例如,为了实现join(),用户需要设计两种map()函数,一个处理第1张表,另一个处理第2张表,还需要精心设计reduce()函数,使得能够分辨来自不同表的数据,进行最后的join()。简而言之,编程较为困难,就像使用没有库函数的C语言来编程。
为了解决这个问题,研究人员的想法是,提供更高层的操作函数来屏蔽Map—reduce的实现细节。那么如何设计这些高层函数呢?我们通过回想普通语言来研究。例如,Java是怎么方便编程的?Java语言通过提供常用的数据结构,如Array、HashMap等来方便用户组织数据,并在数据结构上提供常用函数来方便进行数据操作。根据这个思想,Google在MapReduce编程模型之上设计了FlumeJava,提供了典型数据结构来表示输入/输出和中间数据,如提供的PCollection<;T>;类似于Java中Collection<;T>;,提供的PTable<;T>;是PCollection<;T>;的子类,类似一个二维表,这些数据结构表示了分布在不同机器上的数据。在这些数据结构上提供常见的数据操作,如parallelDo()、groupByKey()、join()等。这样,用户在设计数据处理流程时,可以更关注需要多少处理步骤,每一步进行什么样的数据操作及得到什么样的数据,而不是关注怎样用两个函数map()和reduce()实现数据处理流程。微软的研究人员也提出了类似的高层语言DryadLINQ,提供IEnumerable<;T>;、DryadTable<;T>;等数据结构,以及类似SQL的select()、GroupBy()、join()等操作。Spark借鉴了这两种编程模型,并提出了RDD的数据结构,以及相应的数据操作,我们在下一章将详细讲述该数据结构和常用的数据操作。