对flow服务和大型文档进行映射化简的方法和服务器集群的制作方法

文档序号:6582871阅读:254来源:国知局
专利名称:对flow服务和大型文档进行映射化简的方法和服务器集群的制作方法
技术领域
本发明涉及用于对例如电子数据交换(EDI)文档这样的大型文档的处理进行映 射化简(MapReduce)的方法、服务器集群和计算机程序。
背景技术
企业环境中的现代软件应用通常被组织成多个子程序,其中每个子程序执行该软 件应用的某些子任务。通常,例如在不同企业的应用之间的通信领域中,这种应用必须处理 巨大量的数据,其中必须发送和处理大型文档。 这种应用通常是在集成服务器上执行的,集成服务器的一个示例是申请人的 webMethods集成服务器。该集成服务器支持一种图形编程模型FLOW, FLOW用于定义集成服 务器的处理逻辑。FLOW允许将多个FLOW服务图形化地定义为"黑盒"服务以及这些FLOW 服务之间的管道,这些管道用于将数据从一个FLOW服务的输出传递到另一 FLOW服务的输 入。由于FLOW是图形编程语言,因此它减轻了开发者编写复杂且易出错的传统代码的负 担。FLOW服务可用于处理任何种类的信息并用于执行各种计算。 现有技术已知的一种用集成服务器来处理大型文档的常见方法是以顺序方式处 理文档的内容。然而,由于文档的大小可能在千兆字节的范围内,因此这种顺序处理是非常 耗时且处理密集的,并且可能要求特殊的高端硬件,而这种硬件的维护是成本高昂且复杂 的。 另一种现有技术已知的方法是采用代理(broker),该代理将大型文档分发到集成 服务器的多个实例,以便实现某种并行处理。然而,该方法要求额外的并且经常是复杂的消 耗传递中间件,以便在代理和集成服务器实例之间进行通信,这通常会造成较高的网络带 宽要求并且导致对资源的高消耗。另外,该方法通常涉及由代理和集成服务器实例处理多 个大型文档,其中每个大型文档仍由单个集成服务器以顺序方式来处理。
另外,在处理大型输入数据集的领域中,从Google公司的J. Dean等人所著 的文献"M即Reduce-Simplified Data Processing on Large Clusters" (OSDI ' 04: Sixth Symposium on Operating System Design and Implementation, San Francisco, December, 2004)中知道了 一种编程模型和相关联的框架,其被称为MapReduce (映射 化简)。用户定义的映射(map)函数取得输入的对,并产生中间键/值对的一个集合。 MapReduce库把与同一中间键相关联的所有中间值集合在一起,并把它们传递到用户定义 的化简(reduce)函数。化简函数接受一中间键和一个值集合。它将这些值合并在一起以 形成一个可能较小的值集合。通常每次化简调用将产生零个或一个输出值。中间值经由 迭代器被提供到用户的化简函数。这样就允许了处理太大以至于不能装入存储器中的值 列表。以这种编程模型编写的程序可以自动被该框架在不同机器上并行执行。然而,将 MapReduce编程模型用于现有应用上要求对该应用的编程逻辑进行深入的适应性修改以便 符合M即Reduce编程模型。另外,MapReduce是意图用于搜索引擎领域的,在这个领域中,诸如对大批文档中的单词计数、构建web链接的图结构等等之类的专门任务是常见的。
大型文档处理的一个具体示例是电子数据交换(EDI) 。 EDI涉及通过电子手段在 应用之间传输结构化的消息。EDI通常用于在不同企业的应用之间传输诸如发票或购买定 单之类的大型文档。结构化消息的若干种标准化结构是现有技术中已知的,例如ANSI X12、 UCS、VICS、UN/EDIFACT、 ODETTE和EANC0M。对这种大型EDI文档的处理通常涉及上述的缺 点。 因此,本发明所基于的技术问题一方面是提供一种方法和系统,用于以较少的处 理时间和计算工作来处理大型文档尤其是EDI文档,从而至少部分地克服以上说明的现有 技术的缺点。本发明所基于的另一个相关的技术问题是提供一种方法和系统,用于以较少 的处理时间和计算工作来处理FLOW服务的输入,并且其只需要最低限度的适当性修改工 作就可灵活地适应于现有的编程逻辑。

发明内容
根据一个方面,本发明涉及一种用于对电子数据交换(EDI)文档的处理进行映射
化简的方法。在权利要求1的实施例中,该方法包括以下步骤 a.将EDI文档映射到多个中间文档; b.处理中间文档以产生多个中间结果; c.化简多个中间结果以产生多个经化简的中间结果;以及 d.化简经化简的中间结果以产生表示经处理的EDI文档的最终结果。 本发明的第一方面是基于以下认识的,即M即Reduce的概念不仅可用在搜索引擎
的上下文中,而且也可有利地用于企业环境中的EDI文档的处理。因此,大型EDI文档首先
被映射即分割为多个中间文档。映射即分割优选是这样执行的使得每个所得到的中间文
档具有大致相等大小的有效载荷,即,使得当其在该方法的其他步骤中处理时消耗同等量
的处理时间和/或处理资源。 中间文档随后被处理以产生多个中间结果,这优选是并行执行的,以便改善就整 体处理时间而言的处理性能。另外,由于EDI文档被映射到多个通常更小的中间文档,因此 中间文档可通过普通硬件来处理,即不需要采用专门的高端硬件。 在对中间文档进行处理之后,所得到的中间结果被化简以产生多个经化简的中间 结果。化简意味着将相关的中间结果整合为一个经化简的中间结果。此上下文中的"相关" 指的是两个或更多个中间结果源自同一原始EDI文档。 最后,经化简的中间结果在另一个步骤中被化简以产生最终结果。该方法步骤通 常涉及适当地组合经化简的中间结果,以便获得EDI文档处理的最终结果。
如果化简步骤是在不同物理机器上执行的以便实现并行化,则上述的两步化简尤 其有利。在此情况下,由于中间结果在被发送到执行第二化简步骤的另一机器之前已被化 简,因此宝贵的网络带宽可得以节省,因为在机器之间需要传输的结果更少。另外,如果化 简步骤是满足交换律(即,A operation B相当于B operation A)和/或满足结合律(即, A operation (Boperation C)相当于(A operation B) operation C)的操作,贝隨个方面尤 其有利。因此,化简步骤可以按任何顺序并行执行。与两步化简相关联的另一个优点在于 负担即用于执行化简步骤的处理时间可被分摊在多个普通机器上,而不是一个机器在一个大集合上进行化简步骤。第二化简步骤从而可在较小的中间结果集合上执行。
在本发明的另一个方面中,EDI文档(1)可以按下述方式来映射使得中间文档 (lO,ll)中的每一个包括EDI文档(1)的多个交换包封中的至少一个、多个功能组包封中 的至少一个和/或多个事务集包封中的至少一个。因此,映射即分割可在由EDI文档的结 构定义的边界之一处执行,即在事务集包封级上执行、在功能组包封级上执行和/或在交 换包封级上执行。它通常依赖于最终用户用来基于EDI文档的结构定义在哪个边界上分割 EDI文档。例如,如果功能组和/或交换包封包含最优数目的事务来定义合理大小的有效载 荷。 步骤a.和d.,即映射和最终化简,可由服务器集群的主服务器执行,并且步骤 b.和c.,即分别处理和化简中间文档或中间结果,可由该服务器集群的多个从属服务器执 行。每个从属服务器可处理一个或多个中间文档并且化简一个或多个中间结果。通过多个 从属服务器来执行处理是尤其有利的,因为中间文档的处理能够被高度并行化。主服务器 和从属服务器优选是通过网络连接通信的不同物理机器。 例如,如果处理任务是将一列数字{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}加起来,则主 服务器可将中间文档{1,2}委托给从属节点l,将{3,4}委托给从属节点2,将{5,6}委托 给从属节点3,将{7,8}委托给从属节点l,将{9,10}委托给从属节点2,并且将{11,12}委 托给从属节点3。在从属节点1处,中间结果于是将是中间文档的加和对应于{1,2}的3, 以及对应于{7,8}的15。从属节点1上的化简步骤于是将把3和15相加,得到18。相应 地,从属节点2上的化简步骤将把7和19相加以得出26,并且从属节点3将把11和23相 加以得到34。因此,只有三个经化简的中间结果18、26、34需要被传送回主服务器,而不是 传送3、 15、7、 19、 11、 13。在主服务器上执行的最终化简步骤于是将得出78 (18+26+34),这 是期望的结果。 在另一个方面中,该方法还包括以下步骤通过异步调用将中间文档从主服务器 发送到从属服务器。因此,主服务器取得大型EDI文档并将中间文档的处理委托给从属服 务器。EDI文档本身优选地与主服务器保持在一起。异步调用意味着一旦主服务器调用即触 发了从属服务器的处理(这优选由主服务器的线程池来执行),主服务器线程并不等待从 属服务器完成其处理(这将是同步调用),而是主服务器可以立即继续进行其自己的处理, 即随后调用其他从属服务器。此概念进一步增大了本发明的处理速度,因为不存在被阻塞 的主服务器资源(即,等待从属服务器),从而使得能够将任务更快地委托给从属服务器。
或者,EDI文档可被存储在从属服务器可访问的分布式文件系统中,并且该方法还 可包括以下步骤主服务器通过异步调用把对中间文档(10, 11)的引用标记(reference) 发送到从属服务器。如果从属服务器通过直接连接与该分布式文件系统相连接,则这个方 面可以大大加快处理,因为不必通过缓慢的网络连接来发送EDI文档或中间文档。在此情 况下,只有对EDI文档和/或EDI文档的应当被从属服务器处理的部分(g卩,中间文档)的 引用标记需要被传递到从属节点。协同定位(co-location)(即,提供对实际存在于从属节 点本身上的部分的引用标记)尤其有利,因为它节省了许多带宽消耗,因为在机器之间不 发生EDI数据传送。 当处理中间文档时,从属服务器优选地在本地将中间结果存储在存储器或持续性 文件系统中,这些中间结果随后被主服务器所收集。
另外,中间结果中的每一个可包括把相应中间结果与EDI文档联系起来的标识 符。通过使用标识符,这些中间调用结果中的每一个可被追踪到原始调用。标识符可以是例 如随着利用大型EDI文档进行的每次原始调用而增大的计数器。标识符可用于允许在主服 务器调用从属服务器时的异步行为。这个方面可以释放主服务器处的委托线程(在同步模 式中,这些线程必须等待从属服务器执行其处理),从而使得主服务器处的资源利用更好并 且间接地带来了更大的并行化。当主服务器以异步方式将中间结果委托给从属服务器时, 从属服务器从而拥有了将其获得的中间结果追踪回来自主服务器的原始调用的手段。例 如,如果存在要处理的大型EDI文档,则可为该调用创建标识符"12345"。该方法可在将中 间文档委托给从属服务器的同时将该标识符传递到从属服务器。这帮助了在后续化简步骤 中将所有中间结果与原始EDI文档联系起来,因为在从属服务器处可利用此标识符来维护 中间结果。 作为附加或替换,用于执行步骤b.中从属服务器的处理的处理逻辑可在运行时 期间被分发到从属服务器。因此,从属服务器不必拥有执行EDI文档的可执行文件即处理 逻辑的拷贝。这些可执行文件例如可被包括在主服务器的库中并在运行时被散布到从属服 务器。散布优选地是依据当前EDI文档所需的可执行文件来执行的。任何对等框架或专属 机制都可用于共享可执行文件。 另外,本发明涉及一种服务器集群,其包括适合用于执行以上给出的方法中的任 何一种的主服务器和多个从属服务器。 在本发明的另一个方面中,提供了一种用于对FLOW服务的至少一个输入的处理
进行映射化简的方法。在权利要求9的实施例中,该方法包括以下步骤 a.通过映射器服务将FLOW服务的至少一个输入映射到多个中间输入; b.执行FLOW服务的多个实例(F10,F10'),FL0W服务的实例处理中间输入以产生
多个中间结果; c.通过多个第一化简器服务将中间结果化简为多个经化简的中间结果;以及
d.通过第二化简器服务来化简经化简的中间结果以从经化简的中间结果产生 FLOW服务的最终输出。 因此,FLOW服务(不论是新创建的还是现有的FLOW服务),并不以顺序方式来处 理其输入,而是FLOW服务的处理通过上述方法被有效地"并行化"。因此,FLOW服务的输入 不像通常执行的那样被直接馈送到FLOW服务中,而是首先被映射器服务分割成多个中间 输入。在一个实施例中,FLOW服务本身被"克隆",即中间输入被FLOW服务的多个实例所 处理,优选是并行地处理。所得到的中间结果随后被多个第一化简器服务所化简,以便对于 FLOW服务的每个实例获得一个经化简的中间结果。最后,经化简的中间结果被第二化简器 服务所化简,以便提供FLOW服务的最终输出。优选地,第二化简器服务是基于与多个第一 化简器服务相同的实现的,即,所有化简步骤都是由同一化简器服务的多个实例执行的。在 下文中,为清楚起见,所使用的术语"化简器服务"和"化简器服务的实例"是同义的。应当 注意,FLOW服务的整体输入和输出保持相同,只不过处理被并行化了 。
在一个方面中,映射器服务和第二化简器服务是在服务器集群的主服务器上执行 的,并且FLOW服务的多个实例和多个第一化简器服务是在所述服务器集群的多个从属服 务器上执行的。
在另一个方面中,映射器服务的输入签名符合FLOW服务的输入签名。作为附加或 替换,化简器服务的输出签名符合FLOW服务的输出签名。输入签名(或输出签名)优选地 定义作为服务的输入(或输出)提供的变量的数目和类型,因此定义了服务的接口。
由于映射器服务的输入签名优选地符合要并行化的FLOW服务的输入签名这一事 实,因此任何现有的FLOW服务都可被连接到具有相同输入签名的映射器服务。另外,任何 现有的FLOW服务都可被连接到具有相符的输出签名的化简器服务,这意味着任何现有的 FLOW服务都可被嵌入在本方法中,而无需对其输入或输出签名或内部处理逻辑进行适应性 修改。这是尤其有利的,因为它大大增加了本发明的灵活性和可应用性。输入和输出签名 的示例在以下详细描述中给出。 在另一个方面中,FLOW服务的至少一个输入可包括电子数据交换(EDI)文档。因
此,FLOW服务在这个方面中优选适合用于处理EDI文档。当FLOW服务被并行化时,可以
实现EDI文档的尤其高效的处理,这类似于以上进一步给出的那些方面。然而,应当明白,
FLOW服务完全不限于处理EDI文档。相反,FLOW服务适合于处理任何种类的文档,例如XML
文档。另外,不仅可通过FLOW服务处理文档,还可实现任何种类的计算逻辑。 本发明还涉及一种服务器集群,其包括适合用于执行以上给出的方法中的任何一
种的主服务器和多个从属服务器。 最后,提供了一种计算机程序,其包括适合用于实现上述方法中的任何一种的指 令。


在以下详细描述中,参考以下附图进一步描述本发明的当前优选的实施例
图1 :本发明的实施例的示意性概览; 图2 :根据本发明实施例的主服务器和多个从属服务器的示意性概览;
图3 :EDI文档的结构概览; 图4 :示例性FLOW服务及其相关输入和输出;
图5 :另一个用于处理EDI文档的示例性FLOW服务; 图6 :用于指定被映射化简的FLOW服务的属性的图形用户界面的概览;以及
图7 :本发明的实施例的示例性实现方式的类图。
具体实施例方式
在下文中,针对服务器集群根据本发明对大型EDI文档的处理来描述本发明的当 前优选的实施例。如图2中示意性示出的,也被称为网格的服务器集群是一种分布式的计 算平台,其允许并行处理。它通常包括联网的、松散耦合的计算机的集群,这些计算机协同 动作以执行极大的计算或数据密集型任务。应当明白,处理EDI文档仅是本发明的许多种 场景中的一种,任何其他类型的文档也可被处理。另外,本发明不仅可以有利地实现文档处 理,还可以有利地实现任何种类的复杂计算,以下的更多示例性实施例将证实这一点。
EDI文档的一般结构在图3中示意性地示出,图3示出了例如由ANSIASC X12标准 定义的结构。因此,EDI文档包括任意数目的事务,这些事务被按各种包封(envelop)来分 组。在最内部的级别上,事务集由图3所示的ST/SE片段(segment)来标识。ST片段优选地包括事务集ID、控制号码和可选的实现规约参考标记。SE片段优选地包括该事务集中包 括的片段的数目以及与ST片段相同的控制号码。第二包封级别是功能组包封。其目的是 对一次传输内的相似类型的事务集分组。ANSI ASC X12定义了若干个用于对类似的事务集 分组的业务过程,比如规划调度(830)、购买定单(850)、购买定单确认(855)、购买定单改 变(865)、定单状态查询(869)或定单状态报告(870)。 最外部的级别是由ISA和IEA片段定义的交换包封(参见图3)。交换包封优选地 包含了从一个发送者到一个接收者的数据。ISA片段优选为固定长度的片段。ISA/IEA片 段中包含的一些项目是发送者和接收者的结构化的邮箱地址、交换控制号码、交换包封内 的功能组计数、时间/日期戳以及交换包封的版本。 处理这种EDI文档的通常方式可能是将EDI文档的数据映射到另外的格式(例 如,后端系统所要求的格式),或者将来自EDI文档的数据映射到FLOW服务的输入,下文将
进一步概述这一点。 传统的EDI处理通常一次处理一个事务。如果EDI文档大小大约为数百兆字节或 千兆字节,则此处理是非常耗时的。为了在某种程度上减轻这一缺点,通常部署高端服务器 的集群来并行地处理多个EDI文档中的每一个。然而,对高端服务器的采用具有严重的缺 点,例如,如果在处理期间硬件/软件发生故障则复杂度会增大,以及所有者为了维护高端 服务器而成本增加。 本发明定义了一种用于在EDI文档级上并行化处理的方法和服务器集群。从图1
可以看出,主服务器M1首先接收大型EDI文档1。该EDI文档首先在交换包封边界上被映
射即分割成多个中间文档10、 11 。然而,应当明白,取决于EDI文档的类型,在本发明的其他
实施例中EDI文档也可在例如功能组包封级或者甚至在事务集包封级被分割。 甚至更细粒度的方法也适合于本发明,例如在单事务级分割EDI文档,如果EDI文
档中的事务是独立的实体的话。结果,文档可被映射(分块)为非常小的部分,从而带来了
高水平的并行化。 在分割EDI文档之后,主服务器M1将中间文档10、11委托给多个从属服务器Sl、
S2处理。从属服务器Sl、 S2处理中间文档10、11并且产生中间结果20-23。应当注意,对
一个中间文档的每次处理可能产生多个中间结果,下文将进一步说明这一点。 中间结果20-23随后被从属服务器Sl、 S2中的每一个化简,以便优选地在每个从
属服务器S1 、 S2中获得一个经化简的中间结果30 、 31 。 当主服务器M1完成了将中间文档委托给从属服务器S1、S2时,它优选地在从属服 务器S1、 S2中的每一个上发出化简调用。委托优选地是以异步方式调用的,从而使得主服 务器M1(S卩,其线程)可以继续进行其处理而不必等待每个从属服务器S1、S2完成执行,这 一点已在上文中说明了。 主服务器M1发出的化简调用引起从属服务器S1、S2将其各自化简的中间结果30、
31发送回主服务器M1。主服务器M1随后发出另一化简调用以便将收集到的经化简的中间
结果30、31整合为一个最终输出2。输出2于是代表了经处理的EDI文档1。 应当注意,由于从属服务器S1、S2中的每一个仅处理整个EDI文档1的一部分,因
此不需要专门的高端硬件。普通设备可用作从属服务器,这大大降低了整个体系结构的成本。
主服务器和从属服务器的处理优选的由若干个服务来执行。尤其优选的是其 中服务器是webMethods集成服务器的实施例。webMethods集成服务器处于申请人的 webMethods系列产品的核心处。它是基于Java的多平台企业集成引擎,该引擎支持服务的 执行,以执行诸如数据映射和与其他系统的通信之类的集成逻辑。该集成服务器提供了一 种图形编程模型FLOW, FLOW用于执行诸如映射、调用其他服务、循环和分支之类的常见集 成任务。该集成服务器的一些特征包括编写图形FLOW和Java服务,定义和修改文档和映 射逻辑,测试、调试和执行服务,创建和配置恥b服务,以及编辑适配器服务和通知。
图4示出了示例性的简单FLOW服务"sampleFlowService",其取得两个整数 "inputl"和"input2",并且提供两个输出"multiplylntsResult"(将两个输入整数相乘的 结果)和"addlntsResult"(将两个输入整数相加的结果)。当在集成服务器上执行该示 例性FLOW服务时,可向用户提供用于输入这些输入的值的对话,并且可呈现包括计算结果 的另一对话。图4示出了被开发者优选用于指定输入、FLOW服务和输出之间的映射的图形 用户界面。 FLOW服务处理的另一示例是对文件中单词的出现计数。常见的没有并行化的方 法是逐行地读取该文件,将单词作为键添加在HashMap中并将计数作为值添加在HashMap 中。首先,就该键来查询HashM即,并且如果查询返回"皿ll"(空),则计数被置为1。否则, 原始计数被取得,并且它将被递增并被放回HashMap中。当映射器M10和化简器服务R10、 Rll、 R20被编写时,映射器服务可以产生较小的文件作为输出,并且化简器服务仅将输出 HashM即与最终HashM即相组合。因此,进行单词计数的原始FLOW服务的输入/输出签名 保持相同,而只有映射器和化简器操作的逻辑需要被编写。这是本发明的一个尤为有利的 方面,下文将进一步说明这一点。 FLOW服务的另一个示例是EDI文档的处理。图5示出了示例性的FLOW服务 "mainService",其取得EDI文件名作为输入。它通过调用服务"ediToValues"(也在图 5中示出)来将EDI文件格式转换为内部webMethods格式。作为输出,它返回所输入的 EDI文件在转换后是否整体上是有效的。它还可指示出执行服务所消耗的处理时间(图 5中没有示出)。FLOW服务"ediToValues"的输入/输出签名是如下组织的它接受输入 "ediFileName" (EDI文档的文件名)或输入"edidata"(被表示为串的实际EDI数据本 身),这两者是互斥的。如果"printTime"输入被设置,则执行服务所花的时间将被打印出 来。单个输出"isValid"将被输出,以表明EDI文档在转换后是否有效。
由于对上述FLOW服务"ediToValues"的处理顺序地消耗了大量处理时间和资源, 因此以下论证本发明的方法如何被应用到这种现有的FLOW服务上以便高效并且灵活地对 其进行"并行化"。 参考图6,在FL0W服务"ediToValues"的属性面板中,开发者可以提供以下属性
映射器服务用于映射输入数据的有效集成服务器服务
化简器服务用于化简输出数据的有效集成服务器服务
网格使能设置为"真" 扼流(Throttle):包括主服务器和从属服务器在内的并行执行的最大数目
策略此属性指明是将从属服务器的中间结果保存在存储器中(如果它们的大 小可忽略的话)还是将它们持续保留在文件中。
然后本发明使用上述的映射器服务M10(参见图1)来执行将EDI文档1映射到多 个中间文档10、11。映射器服务MIO的输入和输出签名优选地遵循某些规则
映射器服务的输入优选地与被"并行化"的FL0W服务(在该示例中是 "ediToValues")相同。在此情况下,映射器服务接受与服务"ediToValues"的输入相匹配 的输入"ediFileName"。"映射器服务的输出优选地被包裹在名为"servicelnputData"的集成服务器文档 中。"servicelnputData"的内容优选地是被"并行化"的FLOW服务的输入。在该示例中, 映射器服务的输出"edidata"与服务"ediToValues"的输入相匹配。'另外,映射器服务的输出优选地提供布尔型的"isLastSplit"。映射器服务在处 理最后的映射步骤时将该值设置为"真"。映射器服务于是可反复地被调用,直到该值被设 置为"真"为止。 化简器服务R10、 Rll、 R20的输入和输出签名优选地也遵循某些规则"七简器服务的输入被包裹在称为"reducelnputData"的集成服务器文档列表中。
该文档列表优选地是文档阵列。该文档列表中的每个条目的内容可以是要被"并行化"的
FLOW服务的输出。在该示例中,化简器服务的输入"isValid"与服务"ediToValues"的输
出相匹配。 M七简器服务的输入还可提供布尔型的"isLastReduceSt印"。如果化简器处理最 后的化简调用,则该值可被设置为真。这可用于在化简器服务中执行清理活动。
化简器服务的输出应当是要被"并行化"的服务的输出。在该示例中,输出 "isValid"与服务"ediToValues"的输出相匹配。 可以看出,以上定义的映射器和化简器服务符合FLOW服务的输入和输出签名。这 具有这样的优点,即任何现有的FLOW服务都可以很容易地被"并行化",因为FL0W服务本身 的签名和内部处理都不必被适应性修改。映射器和化简器服务只是简单地被分别"插入"在 FLOW服务之前和之后。 如果化简操作是满足结合律和交换律的,则以上给出的方法可被尤为有利地应 用。例如,当计算1至100的范围中的质数的量时,可以采用两个输入分割;第一输入分割 为1至50,第二输入分割为51至100。此示例中的中间输出将为分别表示这两个分割中的 质数数目的"x"和"y"。化简操作将进行加法,该加法是可结合且可交换的。
以上给出的签名符合性是本发明比现有技术已知的传统M即Reduce算法有利的 优点之一。用户编写的传统M即Reduce的映射步骤取得输入的对并产生中间键/值对的 集合,而根据本发明的集成服务器上的映射器服务遵循标准的签名并且只是对输入数据进 行"分块",即分割。另外,传统的M即Reduce的映射步骤通常是在取得输入对并产生中间 键/值对的集合的从属服务器上运行的,其中集成服务器上的映射器服务优选地在主服务 器M1上执行,主服务器M1随后将分块的输入数据委托给从属服务器S 1、 S2以便执行实 际服务。这一点尤其灵活并且使得flow服务易于开发和维护,其若干原因如下在传统的 MapReduce算法中,不存在被"并行化"的服务,而其更确切地说是通过执行期望操作的映 射器和化简器来定义的编程构造。与集成服务器中不同,不存在与期望操作相对应的服务。 这使得所要求保护的方法易于理解并且尤其对用户友好。 至于由用户编写的传统M即Reduce的化简步骤,它取得中间键并且该键的值集合,并且将这些值合并以形成可能较小的值集合。相反,当化简器服务在根据本发明的集成 服务器上执行时,主服务器M1优选地向所有从属服务器Sl、 S2发出化简调用,以整合相关 的中间结果。当从属服务器S1、 S2中的每一个中的化简操作之后主服务器M1从从属服务 器S1、S2取回结果时,主服务器M1在内部将这些结果组合成一个最终结果。这实质上使得 化简操作成为一个两步过程,该过程首先在从属服务器Sl、 S2上执行,然后在主服务器M1 上执行,这节省了网络带宽,从而带来了处理时间的进一步减少以及对资源的更好利用,以 上已对这一点进行了说明。 本发明的服务器集群的其他特征也是可能的。主集成服务器例如可维护一配置文 件,该配置文件包括可用的从属服务器的列表。它可包括主服务器将处理委托给从属服务 器所需要的信息。这个简单的工具很容易被扩展来实现从属节点的动态识别。例如,当从 属服务器启动时,它可以向服务器集群中的所有机器广播其标识,并且主服务器可以将该 从属服务器识别为潜在的从属服务器。 在下文中,给出本发明的实施例的示例性Java实现,其主要组件在图7中示出。然 而,应当明白,本发明既不限于编程语言Java,也不限于下文中示出的具体实现。
图7所示的类JobClient用于定义"作业"(job),该作业代表根据本发明对数据 处理的一次执行。JobClient的示例性实现在以下代码列表中示出 package com. wm. app. b2b. server, mapred ; import com. wm. data. IData ; import com. wm. lang. ns. NSName ; import com. wm. util. UUID ; public class JobClient { private JobConfiguration jobConf = null ; private JoblnProgress joblnProgress = null ; protected NSName mapper = null ; protected NSName reducer = null ; protected NSName mapTaskName = null ; protected int throttle = 0 ; protected boolean ispersistMapIntResult = false ; protected boolean isStoreMapIntResult = false ; protected String jobld = null ; protected ClusterHosts clusterHosts = null ; protected HostSelector hostSelector = null ; public JobClient (NSName mapper, NSName reducer, NSName mapTaskName, int throttle, boolean isPersistMapIntResult) { this, mapper = m即per ; this, reducer = reducer ;
this. m即TaskN咖e = m即TaskN咖e ; this, throttle = throttle ; this. isPersistMapIntResult = isPersistMapIntResult ; jobConf = new JobConfiguration (); clusterHosts = new ClusterHosts (); hostSelector = new RoundRobinHostSelector(); hostSelector. setClusterHosts(clusterHosts); jobConf. readJobConfiguration(clusterHosts); jobld = UUID. generate ();〃比整数好,因为在服务器重启前后它
将是唯一的 } public JobClient (NSName mapper, NSName reducer, NSName mapTaskName, int throttle, boolean isPersistMapIntResult, boolean
isStoreMapIntResult) { this(m即per, reducer, m即TaskN咖e, throttle, isPersistMapIntResult); this. isStoreMapIntResult = isStoreMapIntResult ; } public void submitjob(IData pipeline) { joblnProgress = new JoblnProgress(this, pipeline); joblnProgress. executeAndTrackJob (); } } 可以看出,当JobClient的新的实例通过调用其构造器而被创建时(参见第15页
第17行),它以参数mapper (要用于当前作业的映射器实现)、reducer (要使用的化简器 实现)、throttle (期望的并行服务执行的数目)以及isPersistM即IntResult(中间结果
是应当被存储在从属服务器的存储器上还是存储在持续性的文件系统中)作为输入。当调 用submitjob ()方法时(参见第16页第4行),该方法取得类型为IData的pipeline参 数,该参数优选地包括要处理的输入数据,例如EDI文档的数据。submitjob ()随后创建新 的JoblnProgress实例并且调用其executeAndTrackJob ()方法。 JoblnProgress的示例性实现在以下代码列表中示出 package com. wm.即p. b2b. server, m即red ; import Java. util. ArrayList ; import com. wm. app. b2b. server. InvokeState ; import com. wm. app. b2b. server. Service ; import com. wm. app. b2b. server. Session ;
import com. wm. app. b2b. server. ThreadManager ; import com. wm. data. IData ; import com. wm. data. IDataCursor ; import com. wm. data. IDataUtil ; public class JoblnProgress implements Ru皿able { private TasklnProgress tasklnProgress = null ; private int m即TaskID = 0 ; private int reduceTaskID = 0 ; protected JobClient jobClient = null ; protected TaskTracker taskTracker = new TaskTracker0 s private InvokeState invokeState = null ; private Session session = null ; private boolean isJobDone = false ; IData m即perPipeline = null ; public JoblnProgress (JobClient jobClient, IData m即perPipeline) { this. jobClient = jobClient ; this. mapperPipeline = mapperpipeline ; } public void executeAndTrackJob () { if (InvokeState. getCurrentState () !=皿ll) { invokeState = (InvokeState) InvokeState. getCurrentState (). clone (); } if (InvokeState. getCurrentSession() ! = null) { session = (Session) InvokeState. getCurrentSession (). clone (); } //long startTime = System. currentTimeMillis0 ; ThreadManager. r皿Target (this); synchronized (this) { while (isJobDone == false) { try { this, wait (); } }
} //long endTime = System. currentTimeMillis0 ; //System, out. print In (〃 The time taken in mill
sees:〃 + (endTime -startTime)); } public void r皿() { boolean isAllMapTasksDispatched = false ; ArrayList〈Integer〉m即TaskldsCompleteList = null ; Integer[]m即TaskIdsComplete = null ; IData reducerPipeline = m即perPipeline ; IDateCursor reducerPipelineCur = null ; InvokeState. setCurrentState (invokeState); InvokeState. setCurrentSession(session); tasklnProgress = new TasklnProgress (); int皿mM即TasksComplete = 0 ; while (true) { 〃检查是否分派了所有映射任务 if ( ! isAllMapTasksDispatched) { 〃分割器 mapTaskID++ ; IDateCursor m即perPipelineCursor = m即perPipeline. getCursor(); IDataUtil. put(mapperPipelineCursor, MapReduceConstants. MAP_ITERATI0N, mapTaskID); try { Service, dolnvoke (jobClient. m即per, mapperPipeline); } catch (Exception e) { e. printStackTrace 0 ; break ; } 〃端点服务 IData serviceI叩utData = (IData)IDataUtil. get(mapperPipelineCursor, MapReduceConstants. SERVICE_INPUT_DATA); IDataUtil. remove(mapperPipelineCursor,
M即ReduceConstants. SERVICE—INPUT—DATA); isAllM即TasksDispatched = IDataUtil. get (mapperPipelineCursor, MapReduceConstants. IS—UVST—SPUT)
null 7 false:true ; if(isAllMapTasksDispatched){ IDataUtil. remove (m即perPipelineCursor, MapReduceConstants. IS_LAST_SPLIT); IDataUtil. remove (m即perPipelineCursor, MapReduceConstants. MAP_ITERATI0N);
} m即perPipelineCursor. destroy 0 ; //System, out. println(〃 spawning map
task:" + mapTaskID); MapTask mapTask = TaskFactory.
createM即Task (this,
mapTaskID); m即Task. setTasklnput (servicelnputData) 5 mapTask. setHostSelector (jobClient.
hostSelector); 〃扼制并行执行的mapTask的最大数目 〃它考虑了先前提交和完成的映射任务 synchronized (taskTracker){ try { 皿mM即TasksComplete = taskTracker. getN咖CompletedM即Tasks (); while ((m即TasklD-皿mM即TasksComple
te) > jobClient. throttle) { //System, out. println
(〃 waiting for some map tasks to complete,皿m mapTasks onGoing: 〃 +(mapTaskID_
皿mM即TasksComplete)); taskTracker. wait(); 皿mM即TasksComplete = taskTracker. getN咖CompletedM即Tasks ();
}
〃待做事项 }
} tasklnProgress. executeTask (mapTask,
invokeState, session); }else if (jobClient. reducer ! = null&& i sAl IMapTasksDi spatched) { 〃化简器 synchronized(taskTracker) { m即TaskIdsCompleteList = taskTracker. getCompletedM即Tasks (); while (mapTaskldsCompleteList = = null | | mapTaskldsCompleteList. size() = = 0) {
try { taskTracker. wait (); } catch (InterruptedExc印tion e) { } m即TaskIdsCompleteList = taskTracker. getCompletedM即Tasks ();
}
} if OnapTaskldsCompleteList ! = null&& mapTaskldsCompleteList. size() 〉 0) { m即TaskIdsComplete = mapTaskldsCompleteList. toArray(new Integer[O]); reduceTaskID+ = m即TaskIdsComplete.
length ^ //System, out. println (〃 processing
reduce tasks:〃 +mapTaskIdsComplete. length); if (m即TaskID == reduceTaskID) { reducerPipelineCur = reducerPipeline. getCursor(); IDataUtil. put(reducerPipelineCur, MapReduceConstants. IS_LAST_REDUCE_STEP, true); reducerPipelineCur. destroy (); } ReduceTask reduceTask =
TaskFactory. createReduceTask(this, reduceTaskID); reduceTask. setTasklnput(reducerPipeline) 5 reduceTask. setCompletedM即Tasks (m即TaskldsComplete); reduceTask. r皿Task () 5 〃如果由于某种原因,化简任务之一返回了
null, 〃此结果不应当造成以前收集的所有其他化
简任务输出无效 〃待做事项当整个框架完成时,失败的(返
回了 null的) 〃化简任务应当被重新执行 IData t卿ReduceOutput = reduceTask. getTaskResult(); if(t卿ReduceOutput ! = null) { reducerPipel ine =
tempReduceOutput ; }
} 〃所有映射和化简任务完成 if (isAllMapTasksDispatched && mapTaskID == reduceTaskID) { IDataCursor reduceServicePipelineCur = reducerPipeline. getCursor0 ; IData reducelntermediateOutput = (IData)IDataUtil. get(reduceServicePipelineCur,
MapReduceConstants. SERVICE_0UTPUT_DATA); IDataUtil. remove(reduceServicePipelineC
ur, MapReduceConstants. SERVICE_0UTPUT_DATA); IDataUtil. remove(reduceServicePipelineC
ur, MapReduceConstants. IS_LAST_REDUCE_STEP); reduceServicePipelineCur. destroy 0 ; 〃将最终结果合并成管道数据 IDataUtil.
merge (reduceIntermediateOutput, m即perPipeline); break ;
} } } final String tabSpace = 〃 〃 ; 〃打印映射任务和化简任务的状态 System, out. println(〃Num Map
Tasks:" +mapT3skID+tebSp3ce+ 〃 Num Reduce Tasks:" +reduceTaskID); 〃作业完成即清理 InvokeState. setCurrentState (null); InvokeState. setCurrentSession(null); jobClient. clusterHosts. freeClusterHosts(); synchronized(this){ isJobDone = true ; this. notifyAll (); } } } 可以看出,在此示例中JoblnProgress的run()方法包括用于处理输入文件的主
代码,即分割(参见第18页第32行)、执行"并行化"的flow服务(参见第19页第8行) 和化简(参见第20页第17行)的步骤。 执行映射的M即Task的示例性实现在以下代码列表中示出 package com. wm.即p. b2b. server, m即red ; import com. wm. app. b2b. server. InvokeState ; import com. wm.即p. b2b. server. ThreadManager ; import com. wm. data. IData ; import com. wm. lang. ns. NSName ; public class MapTask extends AbstractTask implements Runnable { public MapTask(int id,TaskTracker taskTracker,NSName mapSvcName,
TaskResultStoreConfig policy)
{ super(id, taskTracker, m即SvcN咖e, policy); } public void r皿Task() { ThreadManager. r皿Target (this) 5 } public void r皿()
{ InvokeState. setCurrentState (invokeState); InvokeState. setCurrentSession(session); taskStatus = new TaskStatus(); IData output = null ; try { output = RPC. remotelnvoke (hostSelector.
getHostlnfoEntry(), serviceName, tasklnput); tasklnput = null ; } catch(Exception e) { output = null ; } storeTaskResult(output); synchronized(taskTracker){ taskTracker. addM即TaskToCompletedList (this) 5 setTaskStatus(TaskStatus. TASK_C0MPLETE); taskTracker. notifyAll (); } InvokeState. setCurrentState (null); InvokeState. setCurrentSession(null); //System, out. println(〃 map task time is:" +toalSvcTime);
}
} 可以看出,当MapTask被执行时,即,当其run()方法被调用时,MapTask调用RPC 类的remote Invoke ()方法(参见第23页第32行),该remote Invoke ()方法取得三个输入 参数hostSelector. getHostlnfoEntry () 、serviceName禾口 tasklnput。 tasklnput是从超 类AbstractTask继承来的属性并且优选地包括要处理的输入,例如EDI文档的数据。
RPC及其remotelnvoke ()方法的示例性实现在以下代码列表中示出
package com. wm.即p. b2b. server, m即red ;importcom.wm.即p. b2b.client-Context ;importcom.wm.即p. b2b.client.ServiceExc印tion ;importcom.wm.即p. b2b.ACLManager ;importcom.wm.即p. b2b.BaseService ;importcom.wm.即p. b2b.Service ;importcom.wm.即p. b2b.invoke. InvokeManagerimportcom.wm. 即p. b2b.ns. Namespace ;importcom.wm.l肌g. ns.NSNameimportcom.wm.date. IDate ^
import com. wm. data. IDataCursor ;
import com. wm. data. IDataUtil ;
public class RPC
{private static final String DEFAULT_RPC_SERVER =〃 localhost"private static final int DEFAULT_RPC_P0RT = 5555 ;private static final String DEFAULT_RPC_UID =〃 Administrator";private static final String DEFAULT_RPC_PASSWD =〃 manage";private static String rpcServer = null 5private static int rpcPort = _1 jprivate static String rpcUID = null ;private static String rpcPasswd = null ;private static Objectlock = new Object();public static IData remotelnvoke(Hostlnfo hostInfoEntry,NSNamemapTaskName, IData input)throws Exception
if (hostlnfoEntry == null) {return皿ll jboolean isPrimary = hostlnfoEntry. isPrimary0 5if (isPrimary){return Service, dolnvoke (m即TaskN咖e, input) 5)else {Context context = null ;〃在这里同步,否则可能为主机创建不止一个上下文synchronized(lock) {if ( ! hostlnfoEntry. isCo皿ected) {String hostName = hostlnfoEntry
getHostName ();
int port = hostlnfoEntry. getPort();context = new Context ();context, connect (hostName+〃 〃 +port, DEFAULT_RPC_UID, DEFAULT
RPC—PASSWD)hostlnfoEntry. setContext (context);hostlnfoEntry. setCo皿ected (true);}else {context = hostlnfoEntry. getContextO ;
if (context ! = null) { return context, invoke (mapTaskName, input); } } return null ; } } ReduceTask的示例性实现在以下代码列表中示出 package com. wm. app. b2b. server, mapred ; import com. wm. app. b2b. server. Service ; import com. wm. data. IData ; import com. wm. data. IDataCursor ; import com. wm. data. IDataUtil ; import com. wm. lang. ns. NSName ; public class ReduceTask extends AbstractTask { private Integer[] mapTaskIDArray = null ; private boolean inMemory = false ; public ReduceTask(int id,TaskTracker taskTracker, NSName reduceSvcName, TaskResultStoreConfig resultStoragePolicy) { super(id, taskTracker, reduceSvcName, resultStoragepolicy); if (resultStoragePolicy instanceof
TaskResultMemStoreConfig) { inMemory = true ; } } public void setCompletedM即Tasks (Integer []m即TaskIDArray) { this. mapTaskIDArray = mapTaskIDArray ; } public void r皿Task() { if (mapTaskIDArray = = null | | mapTaskIDArray. length = = 0) return ; } if (inMemory) { invokeReduceService(mapTaskIDArray); }
else { IDataCursor reduceServicePipelineCur = tasklnput. getCursor0 ; boolean isLastReduceBatch = IDataUtil. getBoolean(reduceServicePipelineCur, MapReduceConstants. IS_LAST_REDUCE_STEP); IDataUtil. remove(reduceServicePipelineCur, MapReduceConstants. IS_LAST_REDUCE_STEP); reduceServicePipelineCur. destroy 0 ; for(int i = 0 ;i < m即Task皿rray. length ;i++) { if (i == mapTaskIDArray. length-l && isLastReduceBatch){ reduceServicePipelineCur = tasklnput. getCursor0 ; IDataUtil. put (reduceServic印ipelineCur, MapReduceConstants. IS_LAST_REDUCE_STEP, true); reduceServic印ipelineCur. destroy 0 ; } invokeReduceService(newlnteger [] {mapTaskIDArray[i]}); } } storeTaskResult(taskl即ut); } private void invokeReduceService (Integer []m即TaskIDs) { IData[]reduceI即utDataArray = null ; IDataCursor reduceServicePipelineCur = taskl即ut. getCursor (); IData reducelntermediateOutput = (IData)IDataUtil. get(reduceServicePipelineCur, MapReduceConstants. SERVICE_0UTPUT_DATA); int length = 0 ; if(reducelntermediateOutput ! = null){ length = m即TaskIDs. length+1 ; }else { length = m即TaskIDs. length ; } int count = 0 ; reduceInputDataArray = new IData[length];
if (reducelntermediateOutput ! = null) { reducelnputDataArray [count + + ]= reducelntermediateOutput ^ } for (Integer mapTaskID:mapTaskIDs) { synchronized (taskTracker){ reducelnputDataArray[count++]= taskTracker. removeMapTask(mapTaskID). getTaskResult(); } } IDataUtil. put(reduceServicePipelineCur, MapReduceConstants. REDUCE_INPUT_DATA, reducelnputDataArray); if (reducelnputDataArray ! = null) { try{ Service, dolnvoke (serviceName, taskl叩ut); } catch (Exception e) { e. printStackTrace 0 ; } } reducelnputDataArray = null ; IDataUtil. remove (reduceServic印ipelineCur, MapReduceConstants. REDUCE_INPUT_DATA); reduceServicePipelineCur. destroy (); } } MapTask和ReduceTask都以抽象类AbstractTask作为超类,即它们继承其属性以
及set和get方法,这在以下AbstractTask的示例性代码列表中示出 package com. wm. app. b2b. server, mapred ; import com. wm. app. b2b. server. InvokeState ; import com. wm. app. b2b. server. Session ; import com. wm. data. IData ; import com. wm. lang. ns. NSName ; public abstract class AbstractTask implements Task { private int taskID = _1 ; protected TaskStatus taskStatus = null ; protected TaskTracker taskTracker = null ^ protectedlnvokeState invokeState = null ; protected Session session = null ;
protected IData tasklnput = null ; protected NSName serviceName = null ; protected HostSelector hostSelector = null ; private TaskResultStoreConfig taskResultStoreCfg = null ; public AbstractTask(int id,TaskTracker taskTracker, NSName serviceName, TaskResultStoreConfigtaskResultStoreCfg){ this. taskID = id ; this. taskTracker = taskTracker 5 this. serviceName = serviceName ; this. taskResultStoreCfg = taskResultStoreCfg ; } public void setlnvokeState(InvokeState invokeState) { this. invokeState = invokeState ; } public void setlnvokeSession(Session session) { this, session = session ; } public void setTaskID(int taskID) { this. taskID = taskID ; } public int getTaskID() { return taskID ; } public void setTasklnput(IData tasklnput){
this, tasklnput = tasklnput ; } public void setTaskStatus(int status) { taskStatus. setTaskStatus(status); } public void storeTaskResult(IData result){ this. taskResultStoreCfg. storeResult(result); } public IData getTaskResult () { return this. taskResultStoreCfg. fetchResultAndDestroy();
} public void setHostSelector(HostSelector hostSelector) { this. hostSelector = hostSelector ; } } 可以看出,AbstractTask本身实现接口 Task,其示例性实现在以下代码列表中示 出 package com. wm. app. b2b. server, mapred ; import com. wm. app. b2b. server. InvokeState ; import com. wm. app. b2b. server. Session ; import com. wm. data. IData ; public interface Task { public void setlnvokeState(InvokeState invokeState); public void setlnvokeSession(Session session); public void setHostSelector(HostSelector hostSelector); public intgetTaskID(); public void setTaskID(int teskID); public void setTaskStatus(int status); public void setTaskI叩ut (IData taskl叩ut); public void r皿Task(); public void storeTaskResult(IData result); public IData getTaskResult (); } 在本发明的示例性实现中需要若干个其他基础类和接口,它们在以下代码列表中 示出 package com. wm. app. b2b. server, mapred ; import Java. util. ArrayList ; import Java. util. HashMap ; public class TaskTracker { private ArrayList〈Integer〉completedMapTasks = new ArrayList〈Integer〉(); private ArrayList〈Integer〉completedReduceTasks = new ArrayList〈Integer〉(); private Has hMap〈 Integer, MapTask〉 map Results = new
HashMap〈Integer,
MapTask〉();
private HashMap〈Integer, ReduceTask>reduceResults = new
HashMap〈Integer,ReduceTask>(); public ArrayList〈Integer〉getCompletedM即Tasks () { ArrayList〈Integer>ret = completedM即Tasks ; 〃清除原始列表,以便我们只保留新信息 completedMapTasks = new ArrayList〈Integer〉(); return ret ; } public int getNumCompletedM即Tasks () { return completedMapTasks. size (); } public void addM即TaskToCompletedList (M即Task task) { completedMapTasks. add (task. getTaskID ()); mapResults. put (task. getTaskID () , task); } public MapTask removeMapTask(Integer taskID) { return mapResults. remove (taskID); } public ArrayList〈Integer〉getCompletedReduceTasks () { AirayList〈Integer〉:ret = completedReduceTasks ; 〃清除原始列表,以便我们只保留新信息 completedReduceTasks = new ArrayList〈Integer〉(); return ret ; } public int getNumCompletedReduceTasks () { return completedReduceTasks. size (); } public void addReduceTaskToCompletedList(ReduceTask task) { completedReduceTasks. add (task. getTaskID ()); reduceResults. put (task. getTaskID () , task); } public ReduceTask removeReduceTask(Integer taskID)
{ return reduceResults. remove(taskID); }
} package com. wm.即p. b2b. server, m即red ;
/女女 * TaskFactory利用以下配置创建MapTask或ReduceTask * 1.若标志isPersistMapIntResult禾卩isStoreMapIntResult被设置,中间映
射输出将被 *持续保留在$IS_DIR/logs目录中。文件名为I\fap_jobId_taskId或Reduce_jobld—taskld * 2.如果标志isPersistMapIntResult未被设置而标志isStoreMapIntResult被设置,则 *中间映射输出将被保存在存储器中。
* 3.对于所有其他组合,中间映射输出不被存储在文件/存储器中
* / public class TaskFactory{ public static M邻Task createM邻Task(JoblnProgress job, int
taskld){ String tag =〃 Map」'+job. jobClient. jobld+〃 _〃 +taskld ; if(job. jobClient. isPersistMapIntResult){ if (job. jobClient. isStoreMapIntResult){ return new M即Task (taskld, job. taskTracker, job. jobClient. mapTaskName,new TaskResultFileStoreConfig(tag)); } else { return new M即Task (taskld, job. taskTracker, job. jobClient. mapTaskName, new TaskResultNoStoreConfig(tag));
}
}
else{ if(job. jobClient. isStoreMapIntResult) { return new M即Task (taskld, job. taskTracker, job. jobClient. mapTaskName, new TaskResultMemStoreConfig (tag)); } else{ return new M即Task (taskld, job. taskTracker, job. jobClient. mapTaskName, new TaskResultNoStoreConfig(tag));
}
}
} public static ReduceTask createReduceTask(JoblnProgress job, int taskld) { String tag =〃 Reduce_〃 + job. jobCl i ent.
jobld+〃 _〃 +taskld; return new ReduceTask (taskld, job. taskTracker, job. jobClient. reducer, new TaskResultMemStoreConfig (tag));
} } package com. wm. app. b2b. server, mapred ; import com. wm. app. b2b. server. InvokeState ; import com. wm. app. b2b. server. Session ; public class TasklnProgress { public void executeTask(Task task, InvokeState invokeState,
Session session)
{ task. setlnvokeState (invokeState); task. setlnvokeSession(session); task.進Task(); } } package com. wm. app. b2b. server, mapred ; import Java. io. File ; import Java. io. FilelnputStream ; import Java. io. InputStream ; import com. wm. app. b2b. server. Server ; import com. wm. data. IData ; import com. wm. util. coder. IDataXMLCoder ; import com. wm. util. coder. XMLCoderWrapper ; public class TaskResultFileStoreConfig implementsTaskResultStoreConfig{ private File savedFile = null ; private String dataTag = null ; public TaskResultFileStoreConfig(String dataTag){ this. dataTag = dataTag ; }
public IData fetchResultAndDestroy(){ I即utStre咖is = null ; try { XMLCoderWrapper xc = new XMLCoderWrapper (); is = new FilelnputStream(savedFile); return xc. decode (is); } catch (Exception e) { e. printStackTrace (); } finally { try { if (is ! = null) { is. close (); } } catch (Throwable t) { t. printStackTrace (); } finally { savedFile. delete (); } } return null ; } public void storeResult(IData result){ try { savedFile = new File(Server. getLogDir(), dataTag+ 〃 .
xml"); IDataxM!Xoder xc = newIDataXM!Xoder (); xc. writeToFile (savedFile, result); } catch(Exception e) { e. printStackTrace (); } } } package com. wm.即p. b2b. server, m即red ;
import com. wm. data. IData ; public class TaskResultMemStoreConfig implements TaskResultStoreConfig{ private IData result = null ; private String dataTag = null 5 public TaskResultMemStoreConfig(String dataTag){






public void storeResult(IData result) this, result = result ;
public IData fetchResultAndDestroy0 return result 5
this. dateTag = dateTag 5 } } package com. wm. app. b2b. server, m即red ; import com. wm. data. IData ; import com. wm. data. IDataFactory ; public class TaskResultNoStoreConfig implements TaskResultStoreConfig private String dataTag = null 5 public TaskResultNoStoreConfig(String dataTag){ this. dataTag = dataTag 5 } } package com. wm. app. b2b. server, m即red ; import com. wm. data. IData ; public interface TaskResultStoreConfig{
public void storeResult(IData result); public IData fetchReSultAndDestroy0 ;



returnIDataFactory. create();









package com. wm.即p. b2b. server, m即red ; public class TaskStatus
public static final int TASK_DISPATCHED = 1 ; public static final int TASK—RUNNING = 2 ; public static final int TASK_C0MPLETE = 3 ; private int taskStatus = 0 5 public int getTaskStatus()
return teskStetus 5
public static final String MAP—ITERATION =〃 $mapIteration〃 ; public static final String I S_LAST_REDUCE_STEP =〃 isLastReduceSt印〃 ; public static final String REDUCE_ I NPUT_DATA =〃 reducelnputData" 5 public static final String SERVI CE_OUTPUT_DATA =〃 serviceOutputData" 5 public static final String SERVER—ID =〃 id"; public static final String SERVER—HOST =〃 host"; public static final String SERVER—PORT =〃 port"; public static final String IS_PRIMARY = 〃 isPrimary〃 ; public static final String MAPPER =〃 mapper"; public static final String REDUCER =〃 reducer"; public static final String證TASK應E = 〃 mapTaskName〃 ; public static final String THROTTLE =〃 throttle"; } package com. wm. app. b2b. server, m即red ; import Java. io. File ; import Java. io. Fi lelnputStream ; import Java. io. InputStream ; import Java. util. Enumeration ; import Java. util. Properties ; import Java. util. StringTokenizer ; import com. wm. app. b2b. server. Server ; public class JobConfiguration { private static final String CLUSTERED_HOSTS_FILE_NAME = 〃 ClusterHosts. cnf 〃 ; public void readJobConfiguration(ClusterHosts clusterHosts) { try { 〃不改变的默认值。 InputStream fis = new FilelnputStream(new File (Server. getConfDir () , CLUSTERED_HOSTS_FILE_NAME)); Properties prop = new Properties (); prop, load (fis); Enumeration propertyNames = prop. propertyNames(); while (propertyNames. hasMoreElements ()) {
String key = (String) propertyNames.
nextElement(); StringTokenizer values = new StringTokenizer(prop. getProperty(key), 〃 ;〃 ); clusterHosts. addNodeToCluster(key, values. nextToken () , Integer, parselnt (values. nextToken ()), Boolean. parseBoolean (values. nextToken 0)); } } catch (Throwable t) { 〃待做事项 t. printStackTrace(); System, out. println(〃 Error while reading the
clustered hosts properties file〃 );
}
} } package com. wm. app. b2b. server, mapred ; public interface HostSelector { public void setClusterHosts(ClusterHosts clusterHosts); public Hostlnfo getHostlnfoEntry(); } package com. wm. app. b2b. server, mapred ; import com. wm. app. b2b. client. Context ; public class Hostlnfo { boolean isPrimary = false ; String hostDnsName = null ; int port = _1 ; boolean isCo皿ected = false ; Context context = null ; public Hostlnfo(String hostDnsName, int port, boolean isPrimary) { this. hostDnsName = hostDnsName ; this, port = port ; this. isPrimary = isPrimary ; } public String getHostName()
11]]packagimportimportimportimportimportpublic
return hostDnsName ; public int getPort()
return port ; public boolean isPrimary()
return isPrimary ; public boolean isCormected()
return isCormected ; public void setCo皿ected(boolean isCormected)
this. isCormected = isCormected ; public Context getContext()
return context ; public void setCcmtext (Context context) this, context = context ;
protected Map〈String, Hostlnfo〉clusterMap = new LinkedHashMap〈String,
Hostlnfo〉();
protected ArrayList〈HostInfo>hostInfoArrayList = new ArrayList〈HostInfo>(); public void addNodeToCluster(String nodeName, String hostDnsName,
int port,boolean isPrimary)
{ Hostlnfo hostlnfo = new Hostlnfo (hostDnsName, port, isPrimary); clusterMap. put (nodeName, hostlnfo); hostlnfoArrayList. add (hostlnfo); }public void freeClusterHosts()
{ clusterMap. clear (); Iterator iter = hostlnfoArrayList. iterator(); Context context = null ; while (iter. hasNext ()) { Hostlnfo hostlnfo = (Hostlnfo)iter, next (); if (hostlnfo ! = null) { if ( ! hostlnfo. isPrimary){ context = hostlnfo. getContext0 ; context, disconnect 0 ; hostlnfo. setContext(null); hostlnfo. setCo皿ected(false); } } } hostlnfoArrayList. clear(); }
}
权利要求
一种用于对电子数据交换EDI文档(1)的处理进行映射化简的方法,该方法包括以下步骤a.将所述EDI文档(1)映射到多个中间文档(10,11);b.处理所述中间文档(10,11)以产生多个中间结果(20-23);c.化简所述多个中间结果(20-23)以产生多个经化简的中间结果(30,31);以及d.化简所述经化简的中间结果(30,31)以产生表示经处理的EDI文档(1)的最终结果(2)。
2. 如权利要求1所述的方法,其中,所述EDI文档(1)是以下述方式来映射的使得所 述中间文档(lO,ll)中的每一个包括所述EDI文档(1)的多个交换包封中的至少一个、多 个功能组包封中的至少一个和/或多个事务集包封中的至少一个。
3. 如权利要求l或2所述的方法,其中,步骤a.和d.是由服务器集群的主服务器 (Ml)执行的,并且步骤b.和c.是由所述服务器集群的多个从属服务器(Sl, S2)执行的, 每个从属服务器(S1,S2)处理一个或多个中间文档(10, 11)并且化简一个或多个中间结果 (20-23)。
4. 如权利要求3所述的方法,还包括以下步骤通过异步调用将所述中间文档(10, 11) 从所述主服务器(Ml)发送到所述从属服务器(S1, S2)。
5. 如权利要求3所述的方法,其中,所述EDI文档(1)被存储在所述从属服务器(Sl, S2)可访问的分布式文件系统中,并且所述方法还包括以下步骤通过异步调用把对所述 中间文档(10, 11)的引用标记发送到所述从属服务器(S1,S2)。
6. 如前述权利要求中任何一项所述的方法,其中,所述中间结果(20-23)中的每一个 包括把相应中间结果(20-23)与所述EDI文档(1)联系起来的标识符。
7. 如前述权利要求中任何一项所述的方法,其中,用于执行步骤b.中所述从属服务器 (S1,S2)的处理的处理逻辑是在运行时期间被分发到所述从属服务器(S1,S2)的。
8. —种服务器集群,包括适于执行如权利要求1-7中任何一项所述的方法的主服务器 (Ml)和多个从属服务器(Sl, S2)。
9. 一种用于对FLOW服务的至少一个输入(1)的处理进行映射化简的方法,该方法包括 以下步骤a. 通过映射器服务(M10)将所述FLOW服务的至少一个输入(1)映射到多个中间输入 (10,11);b. 执行所述FLOW服务的多个实例(F10,F10'),所述FL0W服务的实例(F10,F10,)处 理所述中间输入(10, 11)以产生多个中间结果(20-23);c. 通过多个第一化简器服务(RIO, Rll)将所述中间结果(20-23)化简为多个经化简 的中间结果(30,31);以及d. 通过第二化简器服务(R20)来化简所述经化简的中间结果(30,31)以从所述经化简 的中间结果(30,31)产生所述FLOW服务的最终输出(2)。
10. 如权利要求9所述的方法,其中,所述映射器服务(M10)和所述第二化简器服务 (R20)是在服务器集群的主服务器(Ml)上执行的,并且所述FLOW服务的多个实例(FIO, F10')和所述多个第一化简器服务(R10,R11)是在所述服务器集群的多个从属服务器(Sl, S2)上执行的。
11. 如权利要求9或10所述的方法,其中,所述映射器服务(M10)的输入签名符合所述 FLOW服务的输入签名。
12. 如权利要求9-ll所述的方法,其中,所述化简器服务(RIO, Rll, R12)的输出签名 符合所述FLOW服务的输出签名。
13. 如权利要求9-12所述的方法,其中,所述FLOW服务的至少一个输入包括电子数据 交换EDI文档(1)。
14. 一种服务器集群,包括适于执行如权利要求9-13中任何一项所述的方法的主服务 器(Ml)和多个从属服务器(Sl, S2)。
15. —种计算机程序,包括适于实现如前述权利要求1-7或9-13中任何一项所述的方 法的指令。
全文摘要
本发明提供了对FLOW服务和大型文档进行映射化简的方法和服务器集群。本发明涉及一种用于对电子数据交换(EDI)文档(1)的处理进行映射化简的方法,该方法包括以下步骤a.将EDI文档(1)映射到多个中间文档(10,11);b.处理中间文档(10,11)以产生多个中间结果(20-23);c.化简多个中间结果(20-23)以产生多个经化简的中间结果(30,31);以及d.化简经化简的中间结果(30,31)以产生表示经处理的EDI文档(1)的最终结果(2)。
文档编号G06Q10/00GK101727481SQ200910207939
公开日2010年6月9日 申请日期2009年11月2日 优先权日2008年10月31日
发明者巴哈斯卡·雷迪·比雷迪, 拉姆·拉玛阿, 维内·普努斯 申请人:软件股份公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1