背景技术
数据处理通常可以刻画为对一个或多个数据集进行多步数据处理操作的流程化处理过程,这些数据处理操作既包含一些通用的关系形式的操作,如:过滤,合并,分组,连接,计数等,也包含一些领域相关的操作,如:语义标注,人脸检测等,我们将这个流程化的数据处理过程称为数据处理流程。常见的数据处理流程应用包括数据仓库应用中的ETL过程,商业智能应用中的数据分析挖掘过程,科学计算领域的科学工作流,搜索引擎领域的大量分析处理过程等,这些典型的应用场景广泛出现在大型企业和科学研究领域.
MapReduce编程模型首先由Google的工程师提出,从用户的角度讲,它将计算过程分为两个最基本的阶段:Map和Reduce,每个阶段的输入都是一系列的键值对(key/value),每个阶段的输出也是一系列的键值对,如下所示:
Map:(k1,v1)→list(k2,v2),接收键值对(k1,v1),经过用户编写的Map代码处理后输出中间键值对(k2,v2),MapReduce系统将自动的根据键对所有中间值进行分组归并,输出键值对(k2,list(v2)),并将其传到Reduce方法中。
Reduce:(k2,list(v2))→list(k3,v3),接收Map阶段输出的键值对(k2,list(v2)),经过用户编写的Reduce代码处理后,将这些值进行合并等操作形成一个更小的值的集合(一般是每个Reduce调用产生0或者1个输出值)。
在信息爆炸的今天,随着数据量的不断增大,数据处理流程越来越呈现出海量和并行的特点,数据格式也以非结构化和结构化的形式出现,而且处理数据的底层系统一般使用集群来搭建,这些对传统的并行数据处理流程实现方法,如:DBMS,网格计算等,提出了新的挑战。而使用MapReduce数据并行计算模型极大的简化了在集群上的海量结构化或者非结构化数据的并行处理过程,而且开源云计算平台Hadoop很好的实现了这一计算模型,满足了大多数用户海量数据处理的需求,并在实际场景中得到了广泛的应用,很多企业,政府,科研机构等都开始使用Hadoop进行海量数据的分析处理。
尽管MapReduce计算模型的提出和Hadoop平台的推出很好的解决了海量数据并行处理的过程,但也正是由于MapReduce模型的简单性导致了一下几方面的问题:
1)不直接支持复杂的n步n分支数据处理流程操作,而这在实际数据处理中是非常常见的。
2)缺少同时处理多个数据集的严格支持能力,必须通过用户自己编程实现,这是一项非常艰难的工作。
3)一些常用的基本数据操作,如:过滤,连接,分组等操作,在每次使用时必须重复的手工编码实现。
最终由于这几个问题的出现,用户在使用MapReduce的实现数据处理流程的过程中总是手工编写各种复杂的数据处理流程,纠缠于多数据源的数据分析,重复的在一些黑盒流程中实现基本的操作,严重限制了MapReduce编程模型的使用,减慢数据分析进度,而且使数据处理程序的可读性大大降低,同时也不可能进行一些自动的流程优化。因此迫切需要一些能够简化基于MapReduce数据处理流程开发的方法及工具
很多科研机构或企业都对简化数据处理流程的MapReduce实现上做了大量的研究,如:Apache的Hadoop,FaceBook的Hive,Yahoo的Pig,Google的Sawzall和FlumeJava等,Hadoop实现了可以在普通的商用机器集群上并行处理海量数据的MapReduce软件框架,Hive提供了基于SQL的简单查询语言Hive QL来简化数据处理流程的操作,同时支持用户自定义的Map和Reduce操作。Pig也是基于Hadoop平台提供了一种类SQL的声明式编程语言pigLatin,Sawzall则提供了一种类C语言的编程方式实现MapReduce,FlumeJava则提供一种通用的接口,但是这些系统和方法普遍存在以下几个问题:
1)没有统一的数据操作组件模型来支持用户自定义数据处理操作。
2)对于普通用户来说使用系统提供的简化MapReduce的编程语言仍然有困难。
3)使用通用的MapReduce流程引擎,由于不同流程的差异性,会导致不必要的判断而带来性能上的损失
4)系统在MapReduce运行参数设置上对用户完全透明,这对于不同的流程执行效率会带来不稳定的影响。
发明内容
针对现有技术中的问题,我们需要一种方法,可以让普通用户通过拖拽数据处理操作组件,连线,以及填写一些配置参数的形式来可视化的设计这个数据处理流程,然后将这个用户设计的这个数据处理流程自动的转换为相应的MapReduce执行代码,从而极大简化用户使用MapReduce并行处理海量数据,提高流程的运行效率。
本发明的目的是提出一种数据处理流程代码的生成方法,这种方法首先将用户通过可视化的方式设计的数据处理流程抽取为一个逻辑模型实例,这个逻辑模型实例保存了流程的数据处理节点信息,节点间的连接信息和流程名,版本等基本信息,然后验证逻辑模型实例是否符合要求,如果不符合则提示用户修改错误,如符合则根据模型转换算法自动的将该逻辑模型实例转换为相应的数据处理流程物理模型,这个物理模型实例保存了流程执行的MapReduce任务拓扑结构,每个任务包含的数据处理节点信息,节点间的连接信息,流程名,版本等基本信息,最后将物理模型实例根据代码生成算法转换为流程的MapReduce实现代码。本发明的技术方案可以表示为图1,具体步骤如下:
1.首先用户使用可视化方式设计数据处理流程,包括提供流程名,版本,数据处理节点,节点连接等信息,然后检查这个数据处理流程是不是一个符合要求的有向无环图的结构,用户配置的信息是否符合相应的数据处理节点和连接的要求等,如果不符合提示用户修改,如果符合则将流程保存为我们定义的特定数据处理流程逻辑模型。
逻辑模型是从用户的视角来定义一个有向无环图,它表示了数据从源端到目的端的一个处理过程,图的节点与节点间传递的数据统一使用二维关系表模式来表示,这种模式的逻辑结构就是一张二维关系表,由行和列构成,每一行是一条数据记录,每条记录由多个数据列构成,每列都包含了列名、数据类型、长度、精度、数据模式等属性,可表示为:R(S*),其中R为表名,S为列,可以表示为一个多元组S=(Name,Type,Pattern,Precision,...),逻辑模型中,V为节点集合,每个节点可以表示为四元组v(v∈V),v=(Id,I,O,L),其中:Id用来标识节点唯一性;I表示的是该节点的一个或者多个输入记录模式集;O表示的是一个或者多个有限输出记录模式集;L表示了该操作的逻辑语义,它包括了该节点需要用户提供的一些逻辑操作参数,如:节点实现的组件ID、过滤条件等,按照输入输出数可以把逻辑模型的节点分为三种:数据源节点,数据装载节点和数据转换节点。数据源节点(起始节点)用来提供关系型记录集,只有输出。数据处理结果装载节点(结束节点),用来存储数据处理结果集,只有输入,转换节点表示数据转换操作,包含输入记录集模式与输出记录集模式的属性映射关系及元组选择条件。逻辑模型中的边为有向边,连接各节点,表示了各个操作之间的依赖关系和数据的流向,可以用多元组(R(S*),VB,VE)来表示,VB为起始节点,VE为结束节点,数据流连接将各个操作之间的依赖关系分为三种:
a)线性关系:表示按线性先后顺序执行的操作序列。
b)多分支聚合关系:某个操作接收多个操作的处理结果进行处理。
c)多分支并发关系:某个操作的处理结果被分为多个分支并发处理。
给定一个用户可视化设计的数据处理流程Ω,它对应的逻辑模型LG(Ω)按照下面的步骤构建:
1)对Ω中每个数据源抽取操作创建一个数据源节点,赋予该数据源节点唯一ID号,数据抽取参数S,抽取参数看数据源的类型而定,如:数据库的话需要用户名,密码,连接URL等,文件的话则需要文件路径等,数据源的输出记录模式集为O,操作语义。
2)对Ω中每一个数据转换操作创建一个转换节点α,并赋予一个唯一的ID号,输入记录模式集为{I1,...,In},输出记录模式集为O,根据其操作语义,生成每个输入记录模式集模式Ik与输出记录模式集模式O的属性映射关系mapping(α,Ik,O)和元组选择条件等。
3)对Ω中每个数据处理结果装载操作创建一个数据装载节点,赋予ID,数据装载参数S,不同的数据源需要配置不同的装置参数,如:数据库需要用户名,密码,连接URL等,以及输入记录模式集I等。
4)根据Ω中数据流向在数据处理节点之间添加有向边,并填充边对应的二维表数据模式信息,得到该可视化数据流程的逻辑模型实例。
2.将第一步构造的逻辑模型实例根据模型转换算法转换为符合物理模型的数据处理流程物理模型实例,物理模型实例也是一个有向无环图的结构,也包含逻辑模型中的三种节点,连接也和逻辑模型实例类似,但是与逻辑模型实例不同的是,物理模型实例中每个节点还包括:
a)MapReduce运行需要的一些配置参数,配置参数根据配置文件以键值对的形式来指定,每个节点都不一样,比如这个操作是只有Map操作的Map节点还是既有Map又有Reduce的MapReduce节点等
b)各个节点进行MapReduce运算需要的map操作代码模板和reduce操作代码模板,以及键/值类型代码模板,物理模型还包括流程公共模板:数据连接模板,流程头部模板,流程尾部模板,MapReduce任务模板,MapReduce任务依赖关系生成模板,任务运行模板,流程尾部代码模板等
在说明具体转换步骤前,我们先引入一个概念“本地节点组”,他用来捕获物理模型实例中以线性方式执行而不存在分支或者聚合的一系列操作节点,在本地节点组的基础上,我们可以来划分MapReduce任务,MapReduce计算模型允许我们通过合并Map操作节点的方式来生成以mapper+/reducer/mapper*形式组织的MapReduce任务,从而减少流程MapReduce任务数,降低磁盘和数据传递消耗,提高效率。具体的模型转换算法执行步骤如下所示:
1)构造一个空的物理模型,它不包含任何节点信息和连接信息,然后填充实现这个数据处理流程需要的一些流程公共模板所在的文件路径信息,这些代码模板包括数据连接模板,流程头部模板,流程尾部模板等,最后还要填充从逻辑模型继承过来的流程名,流程版本等模型公共信息。
2)对逻辑模型实例LG的所有节点进行有向无环图的拓扑排序。
3)按拓扑排序顺序的结果依次遍历每个逻辑节点,读取每个节点的组件ID信息,操作参数信息S,输入模式信息I,输出模式信息O,记录为V1={ID,I,O,S}。
4)根据3)中构造的V1,实例化一个物理节点V2={ID,I,O,S,C},其中ID,I,O,S和V1相同,C则为实现该节点功能的一些代码模板,包括Map操作代码模板,Reduce操作代码模板等。
5)按照遍历的先后顺序连接物理节点,构造物理模型的边信息,得到物理模型有向无环图结构。
6)按照以上构造的物理模型有向无环图结构,提取这个物理模型中的本地节点组信息。
7)针对每个本地节点组提取包含Reduce操作的节点。以Reduce操作节点为划分点,按至少一个map操作连一个reduce操作再连0个或多个map操作的方式(map+/reduce/map*)对本地节点组进行划分,构造相应本地节点组的MapReduce任务集。
8)按照本地节点组之间的连接信息和本地节点组内的连接信息生成各个MapReduce任务之间的依赖关系,最后得到该逻辑模型实例的物理模型实例。
3.将第二步中构造的物理模型实例按照我们设计的代码生成算法生成数据处理流程的MapReduce代码,我们使用Java语言和Hadoop平台提供的MapReduce接口做样例介绍代码生成算法,首先我们介绍数据处理流程的代码结构,每个流程都是一个Java类,数据连接,每个物理节点的Map操作和Reduce操作都作为该类的内部类来实现,对于物理模型中每个MapReduce任务根据其包含的物理节点,使用Hadoop平台提供的ChainMapper和ChainReducer接口组织节点的map操作和reduce操作,并配置好任务的运行参数信息封装出一个Hadoop的JobConf实例,每个流程的代码还包含在一个Java方法runJob,他首先给每个任务构造一个Hadoop Job实例,然后添加每个任务依赖的MapReduce任务,将所有任务通过Hadoop提供的JobControl接口提交,最后在iava方法Main中,构造一个数据处理流程实例对象,并执行这个对象的runJob方法,如附图2所示,
代码生成算法的具体执行步骤如下所示:
1)使用Jet代码生成技术,生成物理模型实例中包含的每个代码模板的模板解析类,包括流程头部模板解析类,数据连接模板解析类,每个节点的输入输出键类型解析类,每个节点的map和reduce操作代码模板解析类等。
2)根据物理模型实例的流程名等信息和流程头部模板解析类生成流程类的头部代码。
3)根据本地节点组之间的连接信息和连接模板解析类生成流程连接内部类代码。
4)按拓扑排序顺序依次遍历物理模型实例PG的每个节点V,根据节点信息生成每个节点的输入输出键类型内部类,Map和Reduce操作内部类代码。
5)声明runJob方法,并在方法体中遍历MapReduce任务集的每个任务,相应的生成任务配置代码,构造所有的任务配置实例(JobConf)实例。
6)在runJob方法中,对每个JobConf实例构造一个Hadoop Job实例,并添加每个任务(Job)依赖的其他Job,从而构建数据处理流程的各个MapReduce任务之间的依赖关系。
7)在runJob方法中将使用Hadoop构造平台提供的JobControl接口提交所有的Job,以便调度任务的运行顺序。
8)在main方法中按照调度任务的运行顺序生成流程执行的入口代码和流程的尾部代码。
本发明的积极效果为:
采用本发明的方法,用户在用可视化的工具设计好一个数据处理流程后,系统将自动将这个流程转换为mapreduce执行代码,并提交到实现了mapreduce的云平台中运行,大大降低了用户开发基于分布式集群的海量数据处理流程的难度,加快了数据分析的进度。此外由于系统使用统一的模型来定义数据处理流程操作,用户可以将自己开发的mapreduce操作方便的集成进来,而且又有使用模型驱动和代码生成技术,可以对数据处理流程进行参数调优配置,代码优化和流程逻辑自动优化等,极大提高流程的执行效率。
具体实施方式
下面结合附图和实施例对本发明做进一步说明。
假定数据库中存有一张客户表和一张订单表,里面存有客户信息和订单信息,大概1亿的用户数据量和70亿的订单量,现在要对这张表做一个如下的统计操作,统计订单总额度最大的前100个客户信息和订单额度信息,同时客户信息中某些字段的格式必须按照修订后的格式显示,如:生日,收入表示等。客户表的结构如下所示:
customer(
c_custkey decimal(9,0)not null,
c_name varchar(25)not null,
c_address varchar(40)not null,
c_birthday datetime not null,
c_phone char(15)not null,
c_income decimal(7,2)not null,
c_comment varchar(117)not null
)
客户表包括客户主键,姓名,地址,生日,联系电话,收入,备注等字段信息
orders(
o_orderkey decimal(12,0)not null,
o_custkey decimal(9,0)not null,
o_orderstatus char(1)not null,
o_totalprice decimal(8,2)not null,
o_orderdate date not null,
o_orderpriority char(15)not null,
o_clerk char(15)not null,
o_comment varchar(79)not null
)
订单表包括订单主键,客户ID,订单状态,订单额度,订单日期,优先级,处理人,备注等字段信息。
以上这个功能可以使用可视化的数据处理流程设计工具设计如图3所示的数据处理流程,具体的操作细节如下:
A1:从数据库中提取订单信息
A2:从数据库中提取客户信息
A3:过滤那些还没有生效的订单
A4:将客户和订单信息按照客户ID做连接操作
A5:对连接后的数据按照客户ID做分组操作
A6:对每个客户ID的分组计算相应的有效订单总额
A7:按照额度对客户信息进行排序操作
A8:提取前100个客户的信息和总额度信息
A9:将A8提取的数据保存在数据库中对于以上这个数据处理流程,我们可以按照如下的方式来生成这个流程的MapReduce实现代码:
1.构造图3对应的数据处理流程的逻辑模型,逻辑模型定义了数据处理操作的执行顺序和操作语义(指这个数据处理操作实现的功能)。将图3所示的数据处理流程转换为逻辑模型:
流程信息:流程名,创建时间,创建人,版本号等
节点信息:
A1:数据源节点
操作参数:数据库连接用户名,密码,url,表名等
输出模式:customer(c_custkey,......,c_comment);
输入模式:空
操作语义:数据库抽取操作
A2:数据源节点
操作参数:数据库连接用户名,密码,url,表名等
输出模式:orders(o_orderkey,......,o_comment);
输入模式:空
操作语义:数据库抽取操作
A3:转换节点
元组条件:订单状态为已完成(o_orderstatus=1)
输入模式:orders(o_orderkey,......,o_comment);
输出模式:orders(o_orderkey,......,o_comment);
操作语义:过滤操作
映射关系:按字段名一一映射
A4:转换节点
元组条件:joinkey=“c_custkey,o_custkey”
输入模式:orders(o_orderkey,......,o_comment);
customer(c_custkey,......,c_comment);
输出模式:orders_customer(o_orderkey,......,o_comment,c_custkey,......,c_comment).
操作语义:数据连接操作
映射关系:按字段名一一映射
A5:转换节点
元组条件:group=c_custKey,按照客户ID分组
输入模式:orders_customer(o_orderkey,......,o_comment,c_custkey,......,c_comment).
输出模式:group_orders_customer(o_orderkey,......,o_comment,c_custkey,......,c_comment).
操作语义:分组操作
映射关系:按照字段名一一映射
A6:转换节点
元组条件:累加o_totalprice字段的值
输入模式:group_orders_customer(o_orderkey,......,o_comment,c_custkey,......,c_comment).
输出模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
操作语义:统计操作
映射关系:按照字段名一一映射
A7:转换节点
元组条件:按照o_totalprice字段值排序
输入模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
输出模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
操作语义:排序操作
映射关系:按照字段名一一映射
A8:转换节点
元组条件:取前100
输入模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
输出模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
操作语义:取前n条记录操作
映射关系:按照字段名一一映射
A9:处理结果装载节点
操作参数:数据库用户名,密码,连接url,装载sql语句,装载策略等
输入模式:customer_orderprice(o_totalprice,c_custkey,......,c_comment).
输出模式:空
操作语义:数据库装载操作
连接信息:
每条连接信息包含了起始节点ID,终止节点ID,传输模式信息,在图3所示的数据处理流程逻辑模型中包含8条连接边,起点和终点都对应相应的节点ID,传输模式信息对应起始节点的输出模式信息。
2.根据模型转换步骤一步一步构造逻辑模型对应的物理模型
1)构造一个节点和连接信息都空的物理模型,这个物理模型包括一些模型公共信息:公共代码模板:
头部模板文件:Header.javajet
连接模板文件:Connection.javajet
尾部模板文件:Footer.javajet
MapReduce任务模板:JobInfo.javajet
任务依赖关系生成代码模板:JobDependency.javajet
任务运行代码模板:RunJob.javajet
2)填充从逻辑流程继承过来的一些公共信息,包括流程名等。
3)对逻辑流程节点按照拓扑排序的顺序进行遍历,生成每个物理节点信息和物理连接信息,对于图3的逻辑模型生成的节点信息为:
PA1:继承了逻辑模型中A1节点的操作参数,输入模式,输出模式,元组条件等信息,同时增加MapReduce参数和代码模板信息,主要包括
节点MapReduce类型:Map操作节点
MapReduce实现代码模板:map操作代码模板mapper.javajet
PA2,PA3与PA1类似
PA4:继承了逻辑模型中A3节点的信息,同时增加MapReduce参数和代码模板信息,
MapReduce类型:map和reduce操作
代码模板:mappe.javajet和reduceer.javajet
PA5,PA6,PA7与PA4类似
PA8,PA9与PA1类似
生成的连接信息和逻辑模型的联系信息一样,只不过把起始节点和末端节点设为物理节点对应的ID。
4)按照生成了物理节点信息和连接信息提取本地组信息,图3可以提取出3个本地组,分别为:
组1:PA1,PA3
组2:PA2
组3:PA4,PA5,PA6,PA7,PA8,PA9
5)针对每个本地组,以MapReduce类型的物理节点为划分点按照map+/reduce/map*模式生成MapReduce任务,针对图3的三个本地组,可以分解为如下mapreduce任务:
组1:一个mapreduce任务m1:由PA1和PA3合并而成
组2:一个mapreduce任务m2:由PA2构成
组3:三个MapReduce任务:
m3:PA4
m4:PA5,PA6
m5:PA7,PA8,PA9
6)根据连接信息生成各个MapReduce任务之间的依赖关系:
m3依赖于m1,m2
m4依赖于m3
m5依赖于m4
3.根据代码生成步骤一步一步构造物理模型对应MapReduce代码
1)根据Header.javajet和流程名生成流程头部代码,如下所示:
Public class流程名{
2)根据连接信息和connection.javajet生成连接内部类代码,如下所示:
Public static class连接名1{
String c_custkey;
//其他字段的代码
......
}
Public static class连接名2{
String c_custkey;
//其他字段的代码
......
}
3)按拓扑排序的顺序再根据每个节点包含的代码模板生成键类型代码,map操作代码,
reduce操作代码等,如下所示:
Public static class Key1{
//字段代码
}
Public static class PA1MapClass{
Public void map(Key1 key,Conn1 value){
//map操作代码
Return(key2,value2);
}
}
Public static class MapOutKeyType1{
//字段代码
}
Public static class MapOutValueType1{
//字段代码
}
Public static class PA2ReduceClass{
Public void reduce(MapOutKeyType1 key,List<MapOutValueType1>value){
//reduce操作代码
Return(key3,value3);
}
}
......其他节点与此类似生成代码
4)根据物理模型中生成的每个MapReduce任务信息,依次生成每个MapReduce任务的配置代码,并按照配置生成MapReduce任务,包括map和reduce的组合操作,输入,输出信息等,代码如下所示:
Job getM1Job(){
JobConf conf=new JobConf();
//配置job的输入输出键值类型,map和reduce操作类等信息
......
Return new Job(conf);
}
//其他MapReduce任务的代码与此类似
......
5)使用JobControl接口添加MapReduce任务之间的依赖关系,根据JobDependency.javajet代码模板和任务依赖关系生成如下代码:
Void runJob(){
JobControl jc=new JobControl(″test″);
Job j1=getM1Job();
//其他任务类似
......
J3.addDenpendcyJob(j1,j2);
J4.addDenpendcyJob(j3);
J5.addDenpendcyJob(j5);
jc.run();
}
6)根据RunJob.javajet和流程信息生成main函数流程执行入口代码:
public static void main(String[]args){
流程名 testInstance=new流程名();
testInstance.runJob();
}
7)根据Footer.javajet生成尾部代码:
“}”