本文主要内容:基本的Map-Reduce
Map-Reduce 基本原理
面向聚合的数据库能够兴起很大一部分原因是由于集群的增长。数据库运行在集群环境中意味着你要在数据存储方面做出权衡,而不能像过去运行在单机上那么简单了。集群不仅仅改变了数据存储的规则,而且还改变了数据计算的规则。如果你把一大堆数据存在集群上,这时候要想有效的处理数据,那么你就必须要用另外一种不同的思路来组织你的处理流程。
如果是使用那种“集中式的数据库”(centralized database),那么通常你可以有两种方式来处理计算逻辑:要么就是在数据库服务器(database server)自己机器上,要么就是在客户端机器(client machine)上。如果你把计算逻辑运行在客户端机器上,对于你选择编程环境就要灵活很多,而且这样也让计算代码(或叫程序,programs)更容易的被创建或扩展。但这样做也有个不好处,就是你不得不把大量的数据从数据库服务器上拉到客户端来。如果数据量很大的话,那么你还是应该把计算交给数据库服务器端来处理,当然了,这样做就没有自由的选择编程环境和扩展计算程序的优势了,而且也加重了数据库服务器端的负载。
这种情况下,如果你把数据放在集群上,那么你会立马收到一个好消息——就是你可以把计算逻辑分布到n多机器上。然而,你依然要尽量的减少通过网络来传输数据,这个量不能太大,尽可能的不去移动数据,而是在有数据的那个节点上进行数据需要的计算逻辑。
map-reduce模型是一种组织“处理流程”(或者叫“计算逻辑”)的手段(其实就是计算模型),是一种利用集群上多机器的优点,让“计算逻辑”(processing)和“数据”(data)放在同一个节点上的一种手段。这个模型当初是因为Google的MapReduce框架而出名[Dean and Ghemawat]。是一个被广泛使用的开源实现,是Hadoop项目的一部分,虽然好多数据库都有他们自己的实现。和大多数模型一样,他们各自在实现细节上都有所不同,所以我们这里只讨论这个模型的一些共性,一般的概念。map-reduce这个名字暴露了它的来头,这个名字的灵感来源于“函数式编程语言”(functional programming languages)中对集合(collections)的map和reduce操作。
7.1. Basic Map-Reduce 基本的Map-Reduce
为了解释清楚它的基本思路,我们将会从之前举的那个老掉牙的例子开始——客户信息(customers)和订单(orders)。现在让我们假定我们选择订单(orders)作为我们的聚合,每条订单里包含商品信息。每个商品信息又有产品id(product ID),数量(quantity)以及单价(price)这么几项。以订单为聚合单元是比较合理的,因为很多时候人们希望一次性查看自己所有的订单。我们拥有很多的订单数据,所以我们把这些订单数据分片后分布到很多台机器上。
然而,销售分析人员却想要查询一个产品过去一周的时间里的销售总额。这个报表并不符合我们的聚合结构,我们的聚合结构是以订单为聚合结构的——这也是使用聚合的缺点所在。但我们还是要满足销售分析人员的需求啊,为了得到产品销售报表,我们就必须去访问集群中的每台机器并在每台机器上查询很多条记录。
这种情况正好可以用map-reduce模型来解决。map-reduce job的第一步自然是map。一个map其实就是一个函数,一个输入参数(input)为一个聚合,然后输出(output)为一堆的key-value对的函数。在我们今天这个例子中,输入参数就是一个订单。输出就是商品项对应的key-value对。每个key-value对 使用产品ID(product ID)作为key,然后是一个包含有数量和单价的嵌套的map作为value(如图7.1)。
图7.1一个map函数从数据库中读取记录,然后输出很多key- value对
map函数所在的每个应用(application)都是独立的。这样他们就可以安全的并发执行了。这样map-reduce框架就可以高效的在每个节点上创建多个map任务(task)了,而且也可以任意的自由的把每个订单分配给某个map任务(task)。这种做法可以利用并发能力访问大量数据,并将数据运算局限在各自的节点上执行。在这个例子中,我们只是选取了记录中的某个值,其实,我们也完全可以随意的将某个复杂的函数作为map的一部分——提不提供这样的函数只是取决于某个聚合的数据的价值。
一个map只操作一条单一的记录;reduce函数则是接受拥有相同key的多个map的输出,然后把这些值合并。所以,一个map函数也许会从针对“Database Refactoring”这本书的订单中产生1000条商品项;reduce函数最后可能就把这么多的记录合并成了一个记录,这条记录中包含了数量(quantity)和销售总额(revenue)。然而,map函数只能操作某个聚合内部的数据,reduce函数则可以操作一个key对应的所有的value。(如图:7.2)
图7.2.一个reduce函数接受那些具有相同key的key-value对,然后把他们合并成一个记录。
map-reduce框架安排map tasks运行在对的节点上来处理所有的文档,安排数据(data)移动到reduce函数那里。为了让你更简单的编写reduce函数,map-reduce框架会将所有的key-value对收集起来,把相同key下的数值汇聚成集合,然后以key与集合组成新的key-value,以这个新的key-value作为reduce函数的输入参数,调用一次reduce函数。所以,要想run map-reduce job,只需要编写这两个函数就可以了。
下集我们主要说有关Partitioning and Combining的内容,敬请期待!
作者简介: