对于那些不太熟悉 SQL 语言的大数据开发人员来说,有没有可能使用一种 GUI(Graphical User Interface,图形用户界面)工具实现上述所有功能呢?下面我就准备开辟一个专题,通过一系列文章,介绍并演示如何用 Kettle 完成这一工作。主要内容包括:
-
ETL 与 Kettle 的基本概念
-
Kettle 及其使用环境的安装与配置
-
Kettle 对 Hadoop 的支持
-
建立 ETL 示例模型
-
数据抽取
-
数据转换与装载
-
定期自动执行ETL作业
-
维度表技术(增加列、维度子集、角色扮演维度、层次维度、退化维度、杂项维度、维度合并、分段维度)
-
事实表技术(周期快照、累计维度、无事实的事实表、迟到的事实、累积度量)
-
Kettle 并行、集群与分区
对于每一种技术,先要理解相关的概念和它之所以出现的原因,这对于我们继续深入学习其技术细节大有裨益。源于一贯的学习方法和习惯,让我们还是先从基本概念开始吧。
一、ETL 基础
ETL 一词是 Extract、Transform、Load 三个英文单词的首字母缩写,中文意为抽取、转换、装载。
-
抽取——从操作型数据源获取数据。
-
转换——转换数据,使之转变为适用于查询和分析的形式和结构。
-
装载——将转换后的数据导入到最终的目标数据仓库。
ETL 是建立数据仓库最重要的处理过程,也是最体现工作量的环节,一般会占到整个数据仓库项目工作量的一半以上。建立一个数据仓库,就是要把来自于多个异构的源系统的数据整合在一起,放置于一个集中的位置用于数据分析。如果一开始这些源系统数据就是兼容的当然最好,但实际情况往往不是这样。ETL 系统的工作就是要把异构的数据转换成同构的。如果没有 ETL,很难对异构数据进行程序化的分析。
1. 数据仓库架构中的 ETL
可以把数据仓库架构理解成构成数据仓库的组件及其之间的关系,那么就有了下面的数据仓库架构图。
图1-1 中显示的整个数据仓库环境包括操作型系统和数据仓库系统两大部分。操作型系统的数据由各种形式的业务数据组成,这其中可能包含关系数据库、TXT 或 CSV 文件、HTML 或 XML 文档,还可能存在外部系统的数据,比如网络爬虫抓取来的互联网数据等。数据可能是结构化、半结构化或非结构化的。这些数据经过 ETL 过程进入数据仓库系统。
这里把 ETL 分成了抽取和转换装载两个部分。抽取过程负责从操作型系统获取数据,该过程一般不做数据聚合和汇总,但是会按照主题进行集成,物理上是将操作型系统的数据全量或增量复制到数据仓库系统的 RDS 中。Hadoop 生态圈中的主要数据抽取工具是 Sqoop。Sqoop 被设计成支持在关系数据库和 Hadoop 之间传输数据。
转换装载过程将数据进行清洗、过滤、汇总、统一格式化等一系列转换操作,使数据转为适合查询的格式,然后装载进数据仓库系统的 TDS 中。传统数据仓库的基本模式是用一些过程将操作型系统的数据抽取到文件,然后另一些过程将这些文件转化成 MySQL 或 Oracle 这样的关系数据库的记录。最后,第三部分过程负责把数据导入进数据仓库。
RDS(Raw Data Stores)是原始数据存储的意思。将原始数据保存到数据仓库里是个不错的想法。ETL 过程的 bug 或系统中的其它错误是不可避免的,保留原始数据使得追踪并修改这些错误成为可能。有时数据仓库的用户会有查询细节数据的需求,这些细节数据的粒度与操作型系统的相同。有了 RDS,这种需求就很容易实现,用户可以查询 RDS 里的数据而不必影响业务系统的正常运行。这里的 RDS 实际上是起到了操作型数据存储(Operational Data Store,ODS)的作用。
TDS(Transformed Data Stores)意为转换后的数据存储,是真正的数据仓库中的数据。大量用户会在经过转换的数据集上处理他们的日常查询。如果前面的工作做得好,这些数据的构建方式将保证最重要的和最频繁的查询能够快速执行。
这里的原始数据存储和转换后的数据存储是逻辑概念,它们可能物理存储在一起,也可能分开。当原始数据存储和转换后的数据存储物理上分开时,它们不必使用同样的软硬件。传统数据仓库中,原始数据存储通常是本地文件系统,数据被组织进相应的目录中,这些目录是基于数据从哪里抽取或何时抽取建立(例如以日期作为文件或目录名称的一部分)。转换后的数据存储一般使用某种关系数据库。在 Hadoop 生态圈中,可以这两类数据逻辑上分开,物理上通过在 Hive 中建立两个不同的数据库来实现,最终所有数据都被分布存储到 HDFS 上。
自动化调度组件的作用是自动定期重复执行 ETL 过程。不同角色的数据仓库用户对数据的更新频率要求也会有所不同,例如财务主管需要每月的营收汇总报告,而销售人员想看到每天的产品销售数据。作为通用需求,所有数据仓库系统都应该能够建立周期性自动执行的工作流作业。ETL 过程自动化是数据仓库成功的重要衡量标准。传统数据仓库一般利用操作系统自带的调度功能(如 Linux 的 cron 或 Windows 的计划任务)实现作业自动执行。Hadoop 生态圈中有一个叫做 Oozie 的工具,它是一个 Hadoop 的工作流调度系统,可以使用它将 ETL 过程封装进工作流自动执行。
数据目录有时也被称为元数据存储,它可以提供一份数据仓库中数据的清单。用户通过它应该可以快速解决这些问题:什么类型的数据被存储在哪里,数据集的构建有何区别,数据最后的访问或更新时间等。此外还可以通过数据目录感知数据是如何被操作和转换的。一个好的数据目录是让用户体验到系统易用性的关键。Hadoop 生态圈中主要的数据目录工具是 HCatalog,它是 Hadoop 上的一个表和存储管理层。
查询引擎组件负责实际执行用户查询。传统数据仓库中,它可能是存储转换后数据的 MySQL、Oracle 等关系数据库系统内置的查询引擎,还可能是以固定时间间隔向其导入数据的 OLAP 立方体,如 Essbase cube。Hadoop 生态圈中的主要 SQL 查询引擎有基于 MapReduce 的 Hive、基于 RDD 的 SparkSQL 和基于 MPP 的 Impala 等。
用户界面指的是最终用户所使用的接口程序。可能是一个 GUI 软件,如 BI 套件的中的客户端软件,也可能就只是一个浏览器。Hadoop 生态圈中比较知名的数据可视化工具是 Hue 和 Zeppelin。
本专题的“
(三)Kettle 对 Hadoop 的支持
” 将详细介绍如何在 Kettle 中使用 Hadoop 相关组件。
2. 数据抽取
抽取操作从源系统获取数据给后续的数据仓库环境使用。这是 ETL 处理的第一步,也是最重要的一步。数据被成功抽取后,才可以进行转换并装载到数据仓库中。能否正确地获取数据直接关系到后面步骤的成败。数据仓库典型的源系统是事务处理应用,例如,一个销售分析数据仓库的源系统之一,可能是一个订单录入系统,其中包含当前销售订单相关操作的全部记录。
设计和建立数据抽取过程,在 ETL 处理乃至整个数据仓库处理过程中,一般是较为耗时的任务。源系统很可能非常复杂并且缺少相应的文档,因此只是决定需要抽取哪些数据可能就已经非常困难了。通常数据都不是只抽取一次,而是需要以一定的时间间隔反复抽取,通过这样的方式把数据的所有变化提供给数据仓库,并保持数据的及时性。除此之外,源系统一般不允许外部系统对它进行修改,也不允许外部系统对它的性能和可用性产生影响,数据仓库的抽取过程要能适应这样的需求。如果已经明确了需要抽取的数据,下一步就该考虑从源系统抽取数据的方法了。
对抽取方法的选择高度依赖于源系统和目标数据仓库环境的业务需要。一般情况下,不可能因为需要提升数据抽取的性能,而在源系统中添加额外的逻辑,也不能增加这些源系统的工作负载。有时,用户甚至都不允许增加任何“开箱即用”的外部应用系统,这被认为是对源系统具有侵入性。下面分别从逻辑和物理两方面介绍数据抽取方法。
(1)逻辑抽取
有两种逻辑抽取类型:全量抽取和增量抽取。
源系统的数据全部被抽取。因为这种抽取类型影响源系统上当前所有有效的数据,所以不需要跟踪自上次成功抽取以来的数据变化。源系统只需要原样提供现有的数据而不需要附加的逻辑信息(比如时间戳等)。一个全表导出的数据文件或者一个查询源表所有数据的 SQL 语句,都是全量抽取的例子。
只抽取某个事件发生的特定时间点之后的数据。通过该事件发生的时间顺序能够反映数据的历史变化,它可能是最后一次成功抽取,也可能是一个复杂的业务事件,如最后一次财务结算等。必须能够标识出特定时间点之后所有的数据变化。这些发生变化的数据可以由源系统自身来提供,例如能够反映数据最后发生变化的时间戳列,或者是一个原始事务处理之外的,只用于跟踪数据变化的变更日志表。大多数情况下,使用后者意味着需要在源系统上增加数据抽取逻辑。
在许多数据仓库中,抽取过程不含任何变化数据捕获技术。取而代之的是,把源系统中的整个表抽取到数据仓库过渡区(Staging Area),然后用这个表的数据和上次从源系统抽取得到的表数据作比对,从而找出发生变化的数据。虽然这种方法不会对源系统造成很大的影响,但显然需要考虑给数据仓库处理增加的负担,尤其是当数据量很大的时候。
(2)物理抽取
依赖于选择的逻辑抽取方法,还有能够对源系统所做的操作和所受的限制,存在两种物理数据抽取机制:直接从源系统联机抽取或者间接从一个脱机结构抽取数据。这个脱机结构有可能已经存在,也可能得需要由抽取程序生成。
数据直接从源系统抽取。抽取进程或者直连源系统数据库访问它们的数据表,或者连接到一个存储快照日志或变更记录的中间层系统(如 MySQL 数据库的 binlog)。注意这个中间层系统并不需要必须和源系统物理分离。
数据不从源系统直接抽取,而是从一个源系统以外的过渡区抽取。过渡区可能已经存在(例如数据库备份文件、关系数据库系统的重做日志、归档日志等),或者抽取程序自己建立。应该考虑以下的存储结构:
-
数据库备份文件。一般需要数据还原操作才能使用。
-
备用数据库。如 MySQL 的数据复制等技术和 Oracle 的 DataGuard。
-
平面文件。数据定义成普通格式,关于源对象的附加信息(列名、数据类型等等)需要另外处理。
-
导出文件。关系数据库大都自带数据导出功能,如 MySQL 的 mysqldump 程序和 Oracle 的 exp/expdp 程序,都可以用于生成数据文件。
-
重做日志和归档日志。每种数据库系统都有自己的日志格式和解析工具。
(3)变化数据捕获
抽取处理需要重点考虑增量抽取,也被称为变化数据捕获(Change Data Capture,CDC)。假设一个数据仓库系统,在每天夜里的业务低峰时间从操作型源系统抽取数据,那么增量抽取只需要过去 24 小时内发生变化的数据。变化数据捕获也是建立准实时数据仓库的关键技术。
当能够识别并获得最近发生变化的数据时,抽取及其后面的转换、装载操作显然都会变得更高效,因为要处理的数据量会小很多。遗憾的是,很多源系统很难识别出最近变化的数据,或者必须侵入源系统才能做到。变化数据捕获是数据抽取中典型的技术挑战。
常用的变化数据捕获方法有时间戳、快照、触发器和日志四种。相信熟悉数据库的用户对这些方法都不会陌生。时间戳方法需要源系统有相应的数据列表示最后的数据变化。快照方法可以使用数据库系统自带的机制实现,如 Oracle 的物化视图技术,也可以自己实现相关逻辑,但会比较复杂。触发器是关系数据库系统具有的特性,源表上建立的触发器会在对该表执行 insert、update、delete 等语句时被触发,触发器中的逻辑用于捕获数据的变化。日志可以使用应用日志或系统日志,这种方式对源系统不具有侵入性,但需要额外的日志解析工作。关于这四种方案的特点,将会在本专题“
(五)数据抽取
”中具体说明。
3. 数据转换
数据从操作型源系统获取后,需要进行多种转换操作。如统一数据类型、处理拼写错误、消除数据歧义、解析为标准格式等等。数据转换通常是最复杂的部分,也是 ETL 开发中用时最长的一步。数据转换的范围极广,从单纯的数据类型转化到极为复杂的数据清洗技术。
在数据转换阶段,为了能够最终将数据装载到数据仓库中,需要在已经抽取来的数据上应用一系列的规则和函数。有些数据可能不需要转换就能直接导入到数据仓库。
数据转换一个最重要的功能是清洗数据,目的是只有“合规”的数据才能进入目标数据仓库。这步操作在不同系统间交互和通信时尤其必要,例如,一个系统的字符集在另一个系统中可能是无效的。另一方面,由于某些业务和技术的需要,也需要进行多种数据转换,例如下面的情况:
-
只装载特定的数据列。例如,某列为空的数据不装载。
-
统一数据编码。例如,性别字段,有些系统使用的是 1 和 0,有些是‘M’和‘F’,有些是‘男’和‘女’,统一成‘M’和‘F’。
-
自由值编码。例如,将‘Male’改成‘M’。
-
预计算。例如,产品单价 * 购买数量 = 金额。
-
基于某些规则重新排序以提高查询性能。
-
合并多个数据源的数据并去重。
-
预聚合。例如,汇总销售数据。
-
行列转置。
-
将一列转为多列。例如,某列存储的数据是以逗号作为分隔符的字符串,将其分割成多列的单个值。
-
合并重复列。
-
预连接。例如,查询多个关联表的数据。
-
数据验证。针对验证的结果采取不同的处理,通过验证的数据交给装载步骤,验证失败的数据或直接丢弃,或记录下来做进一步检查。
4. 数据装载
ETL 的最后步骤是把转换后的数据装载进目标数据仓库。这步操作需要重点考虑两个问题,一是数据装载的效率,二是一旦装载过程中途失败了,如何再次重复执行装载过程。
即使经过了转换、过滤和清洗,去掉了部分噪声数据,但需要装载的数据量还是很大的。执行一次数据装载可能需要几个小时甚至更长时间,同时需要占用大量的系统资源。要提高装载的效率,加快装载速度,可以从以下几方面入手。首先保证足够的系统资源。数据仓库存储的都是海量数据,所以要配置高性能的服务器,并且要独占资源,不要与别的系统共用。在进行数据装载时,可以禁用数据库约束(唯一性、非空性,检查约束等)和索引,当装载过程完全结束后,再启用这些约束,重建索引。这种方法会大幅提高装载速度。在数据仓库环境中,一般不使用数据库来保证数据的参考完整性,即不使用数据库的外键约束,它应该由 ETL 工具或程序来维护。
数据装载过程可能由于多种原因而失败,比如装载过程中某些源表和目标表的结构不一致而导致失败,而这时已经有部分表装载成功了。在数据量很大的情况下,如何能在重新执行装载过程时只装载失败的部分是一个不小的挑战。对于这种情况,实现可重复装载的关键是要记录下失败点,并在装载程序中处理相关的逻辑。还有一种情况,就是装载成功后,数据又发生了改变(比如有些滞后的数据在 ETL 执行完才进入系统,就会带来数据的更新或新增),这时需要重新再执行一遍装载过程,已经正确装载的数据可以被覆盖,但相同数据不能重复新增。简单的实现方式是先删除在插入,或者用 replace into、merge into 等类似功能的操作。
装载到数据仓库里的数据,经过汇总、聚合等处理后交付给多维立方体或数据可视化、仪表盘等报表工具、BI 工具做进一步的数据分析。
5. 开发 ETL 系统的方法
ETL 系统一般都会从多个应用系统整合数据,典型的情况是这些应用系统运行在不同的软硬件平台上,由不同的厂商所支持,各个系统的开发团队也是彼此独立的,随之而来的数据多样性增加了 ETL 系统的复杂性。
开发一个 ETL 系统,常用的方式是使用数据库标准的 SQL 及其程序化语言,如 MySQL 的存储过程、用户自定义函数(UDF)和 Oracle 的 PL/SQL 等。还可以使用 Kettle 这样的 ETL 工具,这些工具都提供多种数据库连接器和多种文件格式的处理能力,并且对 ETL 处理进行了优化。使用工具的最大好处是减少编程工作量,提高工作效率。如果遇到特殊需求或特别复杂的情况,可能还是需要使用 Shell、Java、Python 等编程语言开发自己的应用程序。
ETL 过程要面对大量的数据,因此需要较长的处理时间。为提高 ETL 效率,通常这三步操作会并行执行。当数据被抽取时,转换进程同时处理已经收到的数据。一旦某些数据被转换过程处理完,装载进程就会将这些数据导入目标数据仓库,而不会等到前一步工作执行完才开始。
二、ETL 工具
1. ETL 工具的产生
ETL 工具出现之前,人们使用手工编写程序的方式来完成不同数据源的数据整合工作,常见的程序语言如 COBOL、Perl 或 PL/SQL 等。尽管这种数据整合方案由来已久,但直至今天仍有 ETL 工作使用这种手工编程/脚本的方式来完成。在还没有太多开源 ETL 工具的年代,相对价格昂贵的 ETL 工具而言,手工编程还有一定意义。手工编程的主要缺点在于:
-
容易出错
-
开发周期长
-
不易于维护
-
缺少元数据
-
缺乏一致性的日志和错误处理
最初的 ETL 工具为克服这些问题而被开发,方法是依据设计好的 ETL 工作流来自动生成所需代码。随之出现了 Prism、Carlton、ETI 等产品。代码生成最大的弊端是大多数代码生成仅能用于有限的特定数据库。不久之后,就在代码生成技术广泛应用之时,新的基于引擎架构的 ETL 工具出现了。新一代 ETL 工具可以执行几乎所有的数据处理流程,还可以将数据库连接和转换规则作为元数据存储起来。因为引擎有标准的工作方式,所有的转换在逻辑上是独立的,无论是相对于数据源还是数据目标。基于引擎的 ETL 工具通常比代码生成的方式更具通用性。Kettle 就是一个基于引擎 ETL 工具的典型例子。在这个领域,还有一些其它熟悉的名字,比如 Informatica Powercenter 以及 SQL Server Information Services 等。
无论是代码生成器还是基于引擎的工具,都能帮助我们发现数据源的底层架构,以及这些架构之间的关系。但它们都需要开发目标数据模型,或者先行开发,或者在设计数据转换步骤时开发。设计阶段过后,还必须进行目标数据模型与源数据模型的映射,而整个过程是相当耗时的。所以后来还随之出现了模型驱动的数据仓库工具。模型驱动架构(Model-Driven Architecture,MDA)工具试图自动化实现数据仓库的设计过程,读取源数据模型,生成目标数据模型与需求数据之间的映射,以便向目标表填充数据,但市场上的相关工具并不多。当然 MDA 工具也不可能解决所有的数据集成问题,并且仍然需要具备一定技能的数据仓库开发人员才能发挥其作用。
2. ETL 工具的功能
下面描述一般 ETL 工具必备的通用功能,以及 Kettle 如何提供这些功能。
(1)连接
任何 ETL 工具都应该有能力连接到类型广泛的数据源和数据格式。对于最常用的关系型数据库系统,还要提供本地的连接方式(如 Oracle 的 OCI),ETL 应该能够提供下面最基本的功能:
-
连接到普通关系型数据库并获取数据,如常见的 Oracle、MS SQL Server、IBM DB/2、Ingres、MySQL 和 PostgreSQL 等。
-
从有分隔符或固定格式的 ASCII 文件中获取数据。
-
从 XML 文件中获取数据。
-
从流行的办公软件中获取数据,如 Access 数据库和 Excel 电子表格。
-
使用 FTP、SFTP、SSH 方式获取数据(最好不用脚本)。
除了上述这些功能,还要能从 Web Services 或 RSS 中获取数据。如果还需要一些 ERP 系统里的数据,如 Oracle E-Business Suite、SAP/R3、PeopleSoft 或 JD/Edwards,ETL 工具也应该提供到这些系统的连接。
除了将通用的关系数据库和文本格式的文件作为数据源,Kettle 也提供 Salesforce.com 和 SAP/R3 的输入步骤,但不在套件内,需要额外安装。对于其它 ERP 和财务系统的数据抽取还需要其它解决方法。
(2)平台独立
一个 ETL 工具应该能在任何平台上甚至是不同平台的组合上运行。例如,一个 32 位的操作系统可能在开发的初始阶段运行很好,但是当数据量越来越大时,就需要一个更强大的 64 位操作系统。再比如,开发一般是在 Windows 或 Mac 机上进行的,而生产环境一般是 Linux 系统或集群,ETL 解决方案应该可以无缝地在这些系统间切换。Kettle 是用 Java 开发的,可以运行在任何安装了 Java 虚拟机的计算机上。
(3)数据规模
ETL 解决方案应该能处理逐年增长的数据。一般 ETL 能通过下面三种方式处理大数据。
-
并发:ETL 过程能够同时处理多个数据流,以便利用现代多核的硬件架构。
-
分区:ETL 能够使用特定的分区模式,将数据分发到并发的数据流中。
-
集群:ETL 过程能够分配在多台机器上联合完成。
Kettle 转换里的每个步骤都是以并发的方式来执行,并且可以多线程并行,这样加快了处理速度。Kettle 在运行转换时,根据用户的设置,可以将数据以分发和复制两种方式发送到多个数据流中。分发是以轮流的方式将每行数据只发给一个数据流,复制是将一行数据发给所有数据流。
为了更精确控制数据,Kettle 还使用了分区模式,通过分区可以将同一特征的数据发送到同一个数据流。这里的分区只是概念上类似于数据库的分区,Kettle 并没有针对数据库分区有什么功能,一般认为数据库应该比 ETL 更适合完成数据分区。集群是有效的规模扩展方式,可以使 Kettle 将工作负载按需分配到多台机器上。
本专题的“
(十)并行、集群与分区
”部分深入将论述 Kettle 并行机制,以及集群和分区两种规模扩展方式。
(4)设计灵活性
一个 ETL 工具应该留给开发人员足够的自由度来使用,而不能通过一种固定的方式限制用户的创造力和设计的需求。ETL 工具可以分为基于过程的和基于映射的。基于映射的工具只在源和目的数据之间提供一组固定的步骤,严重限制了设计工作的自由度。基于映射的工具一般易于使用,可快速上手,但是对于更复杂的任务,基于过程的工具才是最好的选择。使用像 Kettle 这样基于过程的工具,根据实际的数据和业务需求,可以创建自定义的步骤和转换。
(5)复用性
设计完的 ETL 转换应该可以被复用,这也是 ETL 工具的一个不可或缺的特征。复制和粘贴已存在的转换步骤是最常见的一种复用,但这还不是真正意义上的复用。复用一词是指定义了一个转换或步骤,从其它地方可以调用这些转换或步骤。Kettle 里有一个“映射(子转换)”步骤,可以完成转换的复用,该步骤可以将一个转换作为其它转换的子转换。另外转换还可以在多个作业里多次使用,同样作业也可以作为其它作业的子作业。
(6)扩展性
ETL 工具必须要有扩展功能的方法。几乎所有的 ETL 工具都提供了脚本,以编程的方式来解决工具本身不能解决的问题。另外有些 ETL 工具可以通过 API 或其它方式来为工具增加组件。第三种方法是使用脚本语言写函数,函数可以被其它转换或脚本调用。
Kettle 提供了上述所有功能。“JavaScript代码”步骤可以用来开发 Java 脚本,把这个脚本保存为一个转换,再通过映射(子转换)步骤,又可以变为一个标准的可以复用的函数。实际上并不限于脚本,每个转换都可以通过这种映射(子转换)方式来复用,如同创建了一个组件。Kettle 在设计上就是可扩展的,它提供了一个插件平台。这种插件架构允许第三方为 Kettle 平台开发插件。Kettle 里的所有组件都是插件,即使是默认提供的组件。
(7)数据转换
ETL 项目很大一部分工作都是在做数据转换。在输入和输出之间,数据要经过检验、连接、分割、合并、转置、排序、归并、克隆、去重、删除、替换或者其它操作。常用的 ETL 工具(包括 Kettle)都提供了下面一些最基本的转换功能:
-
缓慢变更维度(Slowly Changing Dimension,SCD)
-
查询值
-
行列转置
-
条件分割
-
排序、合并、连接
-
聚集
(8)测试和调试
测试和调试的重要性不言而喻。ETL 的设计过程和直接用开发语言写程序很相似,也就是说在写程序时用到的一些步骤或过程同样也适用于 ETL 设计。测试也是 ETL 设计的一部分。为了完成测试工作,我们通常需要假设下面几种失败场景,并要给出相应的处理方法:
-
如果 ETL 过程没有按时完成数据转换的任务怎么办?
-
如果转换过程异常终止怎么办?
-
目标是非空列的数据抽取到的数据为空怎么办?
-
转换后的行数和抽取到的数据行数不一致怎么办(数据丢失)?
-
转换后计算的数值和另一个系统的数值不一致怎么办(逻辑错误)?
测试可分为黑盒测试(也叫功能测试)和白盒测试(也叫结构测试)。对于前者,ETL 转换就被认为是一个黑盒子,测试者并不了解黑盒子内的功能,只知道输入和期望的输出。白盒测试要求测试者知道转换内部的工作机制并依此设计测试用例来检查特定的转换是否有特定的结果。
调试实际是白盒测试中的一部分,通过调试可以让开发者或测试者一步一步地运行一个转换,并找出问题的所在。Kettle 为作业和转换都提供了单步逐行调试功能特性。
(9)血统和影响分析
任何 ETL 工具都应该有一个重要的功能:读取转换的元数据,抽取由不同转换构成的数据流的信息。血统分析和影响分析是基于元数据的两个相关的特性。血统是一种回溯性的机制,它可以查看到数据的来源。例如,“价格”和“数量”字段作为输入字段,在转换中根据这两个字段计算出“金额”字段。即使在后面的处理流程里过滤了“价格”或“数量”字段,血统分析也能分析出“金额”字段是基于“价格”和“数量”字段的。
影响分析是基于元数据的另一种分析方法,该方法可以分析源数据字段对随后的转换以及目标表的影响。本篇后面的“
元数据与资源库
”中将详细讲述 Kettle 的元数据管理。
(10)日志和审计
数据仓库的目的就是要提供一个准确的信息源,因此数据仓库里的数据应该是可靠和可信的。为了保证这种可靠性,同时保证可以记录下所有的数据转换操作,ETL 工具应该提供日志和审计功能。日志可以记录下在转换过程中执行了哪些步骤,包括每个步骤开始和结束时间时间戳。审计可以追踪到对数据做的所有操作,包括读行数、转换行数、写行数。在这方面 Kettle 在 ETL 工具市场处于领先地位。
传统大的软件厂商一般都提供 ETL 工具软件,如 Oracle 的 OWB 和 ODI、微软的 SQL Server Integration Services、SAP 的 Data Integrator、IBM 的 InfoSphere DataStage、Informatica 等。下面介绍本专题的主角,开源 ETL 工具中的佼佼者 —— Kettle。
三、Kettle 简介
Kettle 是 Pentaho 公司的数据整合产品,它可能是现在世界上最流行的开源 ETL 工具,经常被用于数据仓库环境,并可用来操作 Hadoop 上的数据。Kettle 的使用场景包括:不同数据源之间迁移数据、把数据库中的数据导出成平面文件、向数据库大批量导入数据、数据转换和清洗、应用整合等。
Kettle 是使用 Java 语言开发的。它最初的作者 Matt Casters 原是一名 C 语言程序员,在着手开发 Kettle 时还是一名 Java 小白,但是他仅用了一年时间就开发出了 Kettle 的第一个版本。虽然有很多不足,但这版毕竟是可用的。使用自己并不熟悉的语言,仅凭一己之力在很短的时间里就开发出了复杂的 ETL 系统工具,作者的开发能力和实践精神令人十分佩服。后来 Pentaho 公司获得了 Kettle 源代码的版权,Kettle 也随之更名为 Pentaho Data Integration,简称 PDI。
1. Kettle 设计原则
Kettle 工具在设计之初就考虑到了一些设计原则,这些原则也借鉴了以前使用过的其它一些 ETL 工具积累下的经验和教训。
Kettle 认为,作为 ETL 开发者,应该把时间用在创建应用解决方案上。任何用于软件安装、配置的时间都是一种浪费。例如,为了创建数据库连接,很多和 Kettle 类似的 Java 工具都要求用户手工输入数据驱动类名和 JDBC URL 连接串,这明显把用户的注意力转移到了技术方面而非业务方面。Kettle 尽量避免这类问题的发生。
一般 ETL 工具提供了标准化的构建组件来实现 ETL 开发人员不断重复的需求。当然可以通过手工编写 Java 代码或 Java 脚本来实现一些功能,但增加的每一行代码都给项目增加了复杂度和维护成本。所以 Kettle 尽量避免手工开发,而是提供组件及其各种组合来完成任务。
Kettle 直接把所有功能通过界面的方式提供给用户,节约开发人员或用户的时间。当然专家级的 ETL 用户还是要去学习隐藏在界面后的一些特性。在 Kettle 里,ETL 元数据可以通过 XML 格式表现,或通过资源库,或通过使用 Java API。无论 ETL 元数据以哪种形式提供,都可以百分之百通过图形用户界面来编辑。
ETL 转换里有各种各样的名称,如数据库连接、转换、步骤、数据字段、作业等都要有一个名称。如果还要在命名时考虑一些如长度或字符限制,就会给工作带来一定麻烦。Kettle 具备足够的智能化来处理 ETL 开发人员设置的各种名称。最终 ETL 解决方案应该可以尽可能地自描述,这样可以部分减少文档的需求,进而减少项目维护成本。
Kettle 不需要用户了解转换中某一部分工作是如何完成的,但允许用户看到 ETL 过程中各部分的运行状态。这样可以加快开发速度、降低维护成本。
Kettle 从设计之初就在数据的发送、接收方式上尽可能灵活。Kettle 可以在文本文件、关系数据库等不同目标之间复制和分发数据,从不同数据源合并数据也是内核引擎的一部分,同样很简单。
在一些 ETL 工具里经常可以看到数百行的输入和输出映射,对于维护人员来说这是一个噩梦。在 ETL 开发过程中,字段要经常变动,这样的大量映射也会增加维护成本。Kettle 的一个重要核心原则就是,在 ETL 流程中所有未指定的字段都自动被传递到下一个组件。也就是说输入中的字段会自动出现在输出中,除非中间过程特别设置了终止某个字段的传递。
Kettle 可以被归类为可视化编程语言(Visual Programming Languages,VPL),因为 Kettle 可以使用图形化的方式定义复杂的 ETL 程序和工作流。Kettle 里的图就是转换和作业。可视化编程一直是 Kettle 里的核心概念,它可以让用户快速构建复杂的 ETL 作业,并降低维护工作量。Kettle 中的设计开发工作几乎都可以通过简单的拖拽来完成。它通过隐藏很多技术细节,使 IT 领域更接近于业务领域。
2. 转换
转换(transformation)是 Kettle ETL 解决方案中最主要的部分,它处理抽取、转换、装载各阶段各种对数据行的操作。转换包括一个或多个步骤(step),如读取文件、过滤输出行、数据清洗或将数据装载到数据库等等。
转换里的步骤通过跳(hop)来连接,跳定义了一个单向通道,允许数据从一个步骤向另一个步骤步骤流动。在 Kettle 里,数据的单位是行,数据流就是数据行从一个步骤到另一个步骤的移动。
图1-2 所示的转换从数据库读取数据并写入文本文件。除了步骤和跳,转换还包括了注释(note)。注释是一个文本框,可以放在转换流程图的任何位置。注释的主要目的是使转换文档化。
(1)步骤
步骤是转换的基本组成部分,它以图标的方式图形化地展现,图1-2 中显示了两个步骤,“表输入”和“文本文件输出”。一个步骤有几个关键特性:
-
步骤需要有一个名字,这个名字在转换范围内唯一。
-
每个步骤都会读写数据行。唯一例外是“生成记录”步骤,该步骤只写数据。在本专题的“
(四)建立 ETL 示例模型
”中将看到如何使用“生成记录”步骤生成日期维度数据。
-
步骤将数据写到与之相连的一个或多个输出跳(outgoing hops),再传送到跳的另一端的步骤。对另一端的步骤来说,这个跳就是一个输入跳(incoming hops),步骤通过输入跳接收数据。
-
大多数步骤可以有多个输出跳。一个步骤的数据发送可以被设置为轮流发送或复制发送。轮流发送是将数据行依次发给每个输出跳,复制发送是将全部数据行发送给所有输出跳。
-
在运行转换时,一个线程运行一个步骤或步骤的一份拷贝,如图1-2 中“表输入”步骤左上角的 X4,表示 4 个线程执行该步骤,数据行将复制 4 份。所有步骤的线程几乎同时运行,数据行连续地流过步骤之间的跳。
(2)转换的跳
跳(hop)就是步骤间带箭头的连线,跳定义了步骤之间的数据通路。跳实际上是两个步骤之间的被称为行级(row set)的数据行缓存。行集的大小可以在转换的设置里定义,Kettle 8.3 默认为 10000 行。当行集满了,向行集写数据的步骤将停止写入,直到行集里又有了空间。当行集空了,从行集读取数据的步骤停止读取,直到行集里又有可读的数据行。注意,跳在转换里不能循环,因为在转换里每个步骤都依赖于前一个步骤获取字段。
(3)并行
跳的这种基于行集缓存的规则允许每个步骤都由一个独立的线程运行,这样并发程度最高。这一规则也允许以最小消耗内存的数据流的方式来处理。在数据分析中,我们经常要处理大量数据,所以这种并发低耗内存的方式也是 ETL 工具的核心需求。
对于 Kettle 转换,不可能定义一个步骤在另一个步骤之后执行,因为所有步骤都以并发方式执行:当转换启动后,所有步骤都同时开始,从它们的输入跳中读取数据,并把处理过的数据写到输出跳,直到输入跳不再有数据,就中止步骤的运行。当所有的步骤都中止了,整个转换就中止了。从功能的角度看,转换具有明确的起点和终点。例如,图1-2 里显示的转换起点是“表输入”步骤,因为这个步骤生成数据行。终点是“文本文件输出”步骤,因为这个步骤将数据写到文件,而且后面不再有其它节点。
前面关于步骤并发执行与起点、终点的描述看似自相矛盾,实际上只是看问题的角度不同。一方面,可以想象数据沿着转换里的步骤移动,形成一条行头到尾的数据通路。另一方面,转换里的步骤几乎是同时启动的,所以不可能判断出哪个步骤是第一个启动的步骤。如果想要一个任务沿着指定的顺序执行,就要使用后面介绍的“作业”了。
(4)数据行
数据以数据行的形式沿着步骤移动。一个数据行是零到多个字段的集合,字段包括这里所列的几种数据类型。
-
String:字符类型数据。
-
Number:双精度浮点数。
-
Integer:带符号 64 位长整型。
-
BigNumber:任意精度数值。
-
Date:毫秒精度的日期时间值。
-
Boolean:取值为 true 或 false 的布尔值。
-
Binary:二进制类型,可以包括图形、音视频或其它类型的二进制数据。
每个步骤在输出数据行时都有对字段的描述,这种描述就是数据行的元数据,通常包括下面一些信息:
-
名称:行里的字段名应该是唯一的。
-
数据类型:字段的数据类型。
-
长度:字符串的长度或 BigNumber 类型的长度。
-
精度:BigNumber 数据类型的十进制精度。
-
掩码:数据显示的格式(转换掩码)。如果要把数值型(Number、Integer、BigNumber)或日期类型转换成字符串类型就需要用到掩码,例如在图形界面中预览数值型、日期型数据,或者把这些数据保存成文本或 XML 格式时。
-
小数点:十进制数据的小数点格式。不同文化背景下小数点符号是不同的,一般是点(.)或逗号(,)。
-
分组符号(数字里的分割符号):数值类型数据的分组符号,不同文化背景下数字里的分组符号也是不同的,一般是逗号(,)或点(.)或单引号(')。
-
初始步骤:Kettle 在元数据里还记录了字段是由哪个步骤创建的,可以让用户快速定位字段是由转换里的哪个步骤最后一次修改或创建。
当设计转换时有几个数据类型的规则需要注意:
-
行集里的所有行都应该有同样的数据结构。当从多个步骤向一个步骤里写数据时,多个步骤输出的数据行应该有相同的结构,即字段名、数据类型、字段顺序都相同。
-
字段元数据不会在转换中发生变化。字符串不会自动截去长度以适应指定的长度,浮点数也不会自动取整以适应指定的精度。这些功能必须通过一些指定的步骤来完成。
-
默认情况下,空字符串被认为与 NULL 相等,但可以通过 kettle.properties 文件中的 kettle_empty_string_differs_from_null 参数来设置。
(5)数据类型转换
既可以显式地转换数据类型,如在“字段选择”步骤中直接选择要转换的数据类型,也可以隐式地转换数据类型,如将数值数据写入数据库的 varchar 类型字段。这两种形式的数据转换实际上是完全一样的,都是使用了数据和对数据的描述。
Kettle 内部的 Date 类型里包含了足够的信息,可以用这些信息来表现任何毫秒精度的日期、时间值。如果要在 Date 和 String 类型之间转换,唯一要指定的就是日期格式掩码。表1-1 显示的是几个日期转换例子。
转换掩码(格式)
|
结果
|
yyyy/MM/dd’T’HH:mm:ss.SSS
|
2019/12/06T21:06:54.321
|
h:mm a
|
9:06 PM
|
HH:mm:ss
|
21:06:54
|
M-d-yy
|
12-6-19
|
表1-1 日期转换例子
Numeric 数据(包括 Number、Integer、BigNumber)和 String 类型之间的转换用到的几个字段元数据是:转换掩码、小数点符号、分组符号和货币符号。这些转换掩码只是决定了一个数值如何转换为一个文本格式的字符串,而与数值本身的实际精度和舍入无关。表1-2 显示了几个常用的例子。
值
|
转换掩码
|
小数点符号
|
分组符号
|
结果
|
1234.5678
|
#,###.##
|
.
|
,
|
1,234.57
|
1234.5678
|
000,000.00000
|
,
|
.
|
001.234,56780
|
-1.9
|
#.00;-#.00
|
.
|
,
|
-1.9
|
1.9
|
#.00;-#.00
|
.
|
,
|
1.9
|
12
|
00000;-00000
|
|
|
00012
|
表1-2 数值转换掩码的例子
表1-3 提供了 Boolean 和 String 之间、整型与日期类型之间数据类型转换的列表。
从
|
到
|
描述
|
Boolean
|
String
|
转换为 Y 或 N,如果设置长度大于等于 3,转换为 true 或 false
|
String
|
Boolean
|
字符串 Y、True、Yes、1 都转换为 true,其它字符串转换为 false(不区分大小写)
|
Integer
Date
|
Date
Integer
|
整型和日期型之间转换时,整型就是从1970-01-01 00:00:00 GMT 开始计算的毫秒值。例如 2019-08-11 可以转换成 1565452800,反之亦然
|
表1-3 其它数据类型转换
3. 作业
大多数 ETL 项目都需要完成各种各样的维护任务。例如,当运行中发生错误,要做哪些操作;如何传送文件;验证数据库表是否存在等等。这些操作要按照一定顺序完成,就需要一个可以串行执行的作业来处理。
一个作业包括一个或多个作业项,这些作业项以某种顺序来执行。作业执行顺序由作业项之间的跳(job hop)和每个作业项的执行结果来决定。图1-3 显示了一个典型的装载数据仓库的作业。
(1)作业项
作业项是作业的基本构成部分。如同转换的步骤,作业项也可以使用图标的方式图形化展示。但是作业项有一些地方不同于步骤:
-
步骤的名字在转换中是唯一的,但作业项可以有影子拷贝(shadow copies),如图1-3 中的“错误邮件”。这样可以把一个作业项放在多个不同的位置。这些影子拷贝里的信息都是相同的,编辑了一份拷贝,其它拷贝也会随之修改。
-
在作业项之间可以传递一个结果对象(result object)。这个结果对象里包含了数据行,它们不是以流的方式传递的,而是等一个作业项执行完了,再传递给下一个作业项。
-
默认情况下,所有的作业项都以串行方式执行,只是在特殊的情况下以并行方式执行。
因为作业顺序执行作业项,所以必须定义一个起点,如图中的“start”作业项,就定义了一个起点。一个作业只能定义一个开始作业项。
(2)作业的跳
如同转换中各步骤之间的跳,作业的跳是作业项之间的连接线,它定义了作业的执行路径。作业里每个作业项的不同运行结果决定了作业的不同执行路径。对作业项的运行结果的判断如下:
-
无条件执行:不论上一个作业项执行成功还是失败,下一个作业项都会执行。这是一种黑色的连接线,上面有一个锁的图标,如图1-3 中 “start”到“传送数据”作业项之间的连线。
-
当运行结果为真时执行:当上一个作业项的执行结果为真时,执行下一个作业项,通常在需要无错误执行的情况下使用。这是一种绿色连接线,上面有一个对钩号图标,如图1-3 中横向的三个连线。
-
当运行结果为假时执行:当上一个作业项的执行结果为假或没有成功时,执行下一个作业项。这是一种红色的连接线,上面有一个红色的叉子图标。
在作业跳的右键菜单上可以设置以上这三种判断方式。
(3)多路径和回溯
Kettle 使用一种回溯算法来执行作业里的所有作业项,而且作业项的运行结果(真或假)也决定执行路径。回溯算法是一种深度遍历:假设执行到了图里的一条路径的某个节点时,要依次执行这个节点的所有子路径,直到没有再可以执行的子路径,就返回该节点的上一节点,再反复这个过程。
例如,图1-4 里的 A、B、C 三个作业项的执行顺序为:
-
首先“Start”作业项搜索所有下一个节点作业项,找到了“A”和“C”。
-
执行“A”
-
搜索“A”后面的作业项,发现了“B”。
-
执行“B”。
-
搜索“B”后面的作业项,没有找到任何作业项。
-
回到“A”,也没有发现其它作业项。
-
回到“Start”,发现另一个要执行的作业项“C”。
-
执行“C”。
-
搜索“C”后面的作业项,没有找到任何作业项。
-
回到“Start”,没有找到任何作业项。
-
作业结束。
因为没有定义执行顺序,所以这个例子的执行顺序除了 ABC,还可以是 CAB。这种回溯算法有两个重要特征:
-
因为作业可以是嵌套的,除了作业项有运行结果,作业也需要一个运行结果,因为一个作业可以是另一个作业的作业项。一个作业的运行结果,来自于它最后一个执行的作业项。这个例子里作业的执行顺序可能是 ABC,也可能是 CAB,所以不能保证作业项 C 的结果就是作业的结果。
-
作业里允许循环。当在作业里创建了一个循环,一个作业项就会被执行多次,作业项的多次运行结果会保存在内存里,便于以后使用。
(4)并行执行
一个作业项能以并发的方式执行它后面的作业项,如图1-5 中的作业所示。在这个例子里,作业项 A 和 C 几乎同时启动。
(5)作业项结果
作业执行结果不仅决定了作业的执行路径,而且还向下个作业项传递了一个结果对象。结果对象包括了这里所示的一些信息。
-
一组数据行:在转换里使用“复制记录到结果”步骤可以设置这组数据行。与之对应,使用“从结果获取记录”步骤可以获取这组数据行。在一些作业项里,如“Shell”、“转换”、“作业”的设置里有一个选项可以循环执行这组数据行,这样可以通过参数化来控制转换和作业。
-
一组文件名:在作业项的执行过程中可以获得一些文件名。这组文件名是所有与作业项发生过交互的文件的名称。例如,一个转换读取和处理了 10 个 XML 文件,这些文件名就会保留在结果对象里。使用转换里的“从结果获取文件”步骤可以获取到这些文件名,除了文件名还能获取到文件类型。“一般”类型是指所有的输入输出文件,“日志”类型是指 Kettle 日志文件。
-
读、写、输入、输出、更新、删除、拒绝的行数和转换里的错误数。
-
脚本作业项的退出状态:根据脚本执行后的状态码,判断脚本的执行状态,再执行不同的作业流程。
4. 数据库连接
Kettle 里的转换和作业使用数据库连接来连接到关系型数据库。Kettle 数据库连接实际是数据库连接的描述,也就是建立实际连接需要的参数。实际连接只是在运行时才建立,定义一个 Kettle 的数据库连接并不真正打开一个数据库的连接。各种数据库的行为彼此不同,图1-8 所示的数据库连接窗口里有很多种数据库。
在数据库连接窗口中主要设置三个选项:
-
连接名称:设定一个在作业或转换范围内唯一的名称。
-
连接类型:从数据库列表中选择要连接的数据库类型。根据选中数据库的类型不同,要设置的访问方式和连接参数也不同,某些 Kettle 步骤或作业项生成 SQL 语句时使用的方言也不同。
-
访问方式:在列表里可以选择可用的访问方式,一般都使用 JDBC 连接,不过也可以使用 ODBC 数据源、JNDI 数据源、Oracle 的 OCI 连接(使用 Oracle 命名服务)等。
根据选择的数据库不同,右侧面板的连接参数设置也不同。例如图1-8 中,只有 Oracle 数据库可以设置表空间选项。一般常用的连接参数为:
-
主机名:数据库服务器的主机名或 IP 地址。
-
数据库名:要访问的数据库名。
-
端口号:默认是选中的数据库服务器的默认端口号。
-
用户名和密码:连接数据库服务器的用户名和密码。
对于大多数用户来说,使用数据库连接窗口的“一般”标签就足够了。但偶尔也可能需要设置对话框里的“高级”标签的内容,如图1-9 所示。
-
支持 Boolean 数据类型:对 Boolean(bit)数据类型,大多数数据库的处理方式都不相同,即使同一个数据库的不同版本也可能不同。许多数据库根本不支持 Boolean 数据类型,如 MySQL 和 Oracle,所以默认情况下,Kettle 使用一个 char(1) 字段的不同值(如 Y 或 N )来代替 Boolean 字段。如果选中了这个选项,Kettle 就会为支持 Boolean 类型的数据库生成正确的 SQL 方言。
-
双引号分割标识符:强迫 SQL 语句里的所有标识符(如列名、表名)加双引号,一般用于区分大小写的数据库,或者 Kettle 里定义的关键字列表和实际数据库不一致的情况。
-
强制转为小写:将所有表名和列名转为小写。
-
强制转为大写:将所有表名和列名转为大写。
-
默认模式名:当不明确指定模式名时默认的模式名。
-
连接后要执行的 SQL 语句:一般用于建立连接后,修改某些数据库参数,如 session 级的变量或调试信息等。
除了这些高级选项,在连接对话框的 “选项”标签下,还可以设置数据库特定的参数,如一些连接参数。为了便于使用,对于某些数据库(如 MySQL),Kettle 提供了一些默认的连接参数和值。有几种数据库类型,Kettle 还提供了连接参数的帮助文档,通过单击“选项”标签中的“帮助”按钮可以打开对应数据库的帮助页面。
还可以选择 Apache 的通用数据库连接池选项。如果运行了很多小的转换或作业,这些转换或作业里又定义了生命期短的数据库连接,连接池选项就显得有意义了。连接池选项不会限制并发数据库连接的数量。
当一个大数据库不能再满足需求时,就会考虑用很多小的数据库来处理数据。通常可以使用数据分区技术(注意不是数据库系统本身自带分区特性)来分散数据装载。这种方法可以将一个大数据集分为几个数据分区,每个分区都保存在独立的数据库实例中。这种方法的优点显而易见,能够大幅减少每个表或每个数据库实例的行数。可以在数据库连接对话框的“集群”标签下设置分区,详见本专题的“
(十)并行、集群与分区
”。
关系数据库在数据的连接、合并、排序等方面有着突出的优势。和基于流的数据处理引擎,如 Kettle 相比,它的一大优点是,数据库使用的数据都存储在磁盘中。当关系型数据库进行连接或排序操作时,直接使用这些数据即可,而不用把这些数据装载到内存里,这就体现出明显的性能方面的优势。但缺点也是很明显的,把数据装载到关系数据库里也可能会产生性能的瓶颈。
对 ETL 开发者而言,要尽可能利用数据库自身的性能优势,来完成连接或排序这样的操作。如果不能在数据库里进行连接这样的操作,如数据的来源不同,也应该在数据库里排序,以便在 ETL 里做连接操作。
5. 连接与事务
数据库连接只在执行作业或转换时使用。在作业里,每一个作业项都打开和关闭一个独立的数据库连接。转换也是如此,但是因为转换里的步骤是并行的,每个步骤都打开一个独立的数据库连接并开始一个事务。尽管这样在很多情况下会提高性能,但当不同步骤更新同一个表时,也会带来锁和参照完整性问题。
为了解决打开多个数据库连接而产生的问题,Kettle 可以在一个事务中完成转换。在转换设置对话框的 “杂项”标签中,设置“使用唯一连接”,可以完成此功能。当选中了这个选项,所有步骤里的数据库连接都使用同一个数据库连接。只有所有步骤都正确,转换正确执行,才提交事务,否则回滚事务。
6. 元数据与资源库
转换和作业是 Kettle 的核心组成部分。在介绍 Kettle 设计原则时曾经讨论过,它们可以用 XML 格式来表示,可以保存在资料库里,也可以用 Java API 的形式来表示。它们的这些表示方式,都依赖于这里所列的元数据。
-
名字:转换或作业的名字。不论是在一个 ETL 工程内还是在多个 ETL 工程内,都应该尽可能使用唯一的名字,这样在远程执行时或多个 ETL 工程共用一个资源库时都会有帮助。
-
文件名:转换或作业所在的文件名或 URL。只有当转换或作业是以 XML 文件的形式存储时,才需要设置这个属性。当从资源库加载时,不必设置这个属性。
-
目录:这个目录是指在 Kettle 资源库里的目录。当转换或作业保存在资源库里时设置,保存为 XML 文件时不用设置。
-
描述:这是一个可选属性,用来设置作业或转换的简短的描述信息。如果使用了资源库,这个描述属性也会出现在资源库浏览窗口的文件列表中。
-
扩展描述:也是一个可选属性,用来设置作业或转换的详细描述信息。
当 ETL 项目规模比较大,有很多 ETL 开发人员在一起工作,开发人员之间的合作就显得很重要。Kettle 以插件的方式灵活定义不同种类的资源库,但不论是哪种资源库,它们的基本要素是相同的:它们都使用相同的用户界面、存储相同的元数据。目前有三种常见资源库:数据库资源库、Pentaho 资源库和文件资源库。
-
数据库资源库:把所有的 ETL 信息保存在关系数据库中。这种资源库比较容易创建。
-
文件资源库:在一个文件目录下定义一个资源库。因为 Kettle 使用的是 Apache VFS 虚拟文件系统,所以这里的文件目录是一个广泛的概念,包括 zip 文件、Web 服务、FTP 服务等。
-
Pentaho 资源库:包含在 Kettle 企业版中的一个插件。这种资源库实际是一个内容管理系统(Content Manage System,CMS),它具备一个理想资源库的所有特性,包括版本控制和依赖完整性检查。
无论哪种资源库都应该具有下面的特性:
-
中央存储:在一个中心位置存储所有的转换和作业。ETL 用户可以访问到工程的最新视图。
-
文件加锁:防止多个用户同时修改同一文件。
-
修订管理:一个理想的资源库可以存储一个转换或作业的所有历史版本,以便将来参考。可以打开历史版本,并查看变更日志。
-
依赖完整性检查:检查资源库转换或作业之间的相互依赖关系,可以确保资源库里没有丢失任何链接,没有丢失任何转换、作业或数据库连接。
-
安全性:防止未授权的用户修改或执行 ETL 作业。
-
引用:重新组织转换、作业,或简单重命名,都是 ETL 开发人员的常见工作。要做好这些工作,需要完整的转换或作业的引用。
在下一篇的“
使用资源库
”中将详述 Kettle 资源库的创建、管理与使用。
7. 工具
Kettle 是一个独立的产品,但它包括了 ETL 开发和部署阶段用到的多个工具程序,主要包括:
-
Spoon:图形化工具,用于快速设计和维护复杂的 ETL 工作流。
-
Kitchen:运行作业的命令行工具。
-
Pan:运行转换的命令行工具。
-
Carte:轻量级(大概 1MB)Web 服务器,用来远程执行转换或作业。一个运行有 Carte 进程的机器可以作为从服务器,从服务器是 Kettle 集群的一部分。
每个工具都有独立的功能,也多少依赖于其它程序。Kettle 的主体框架如图1-10 所示。
图1-11 里可以清楚地看到 Spoon 的主窗口。主窗口上方有一个菜单条,下方是一个左右分隔的应用窗口。右方面板里有多个标签面板,每个标签面板都是一个当前打开的转换或作业。左方面板是一个树状结构步骤或作业项视图。右方的工作区又可以分为上下两个部分:上部的画布和下部的结果面板。
图1-11 的当前选中的画布标签里显示了一个设计好的转换。设计作业或转换的过程实际就是往画布里添加作业项或转换步骤的图标这么简单,向画布添加图标的方式为,从左侧的树中拖拽。这些作业项和转换步骤通过跳来连接。跳就是从一个作业项/步骤的中心连接到另一个作业项/步骤的一条线。在作业里跳定义的是控制流,在转换里跳定义的是数据流。工作区下方的面板是运行结果面板,其中除了显示运行结果还显示运行时日志和运行监控。
工作区左侧的树有“主对象树”和“核心对象”两个标签。主对象树将当前打开的作业或转换里的所有作业项或步骤以树状结构展现。设计者可以在这里快速地找到某个画布上的步骤、跳或数据库连接等资源。核心对象中包含 Kettle 中所有可用的作业项或步骤,可以在搜索框中输入文本查找名称模糊匹配的作业项或步骤。一些调试作业/转换的工具也集成到了 Spoon 的图形界面里,设计者可以在 IDE 里直接调试作业/转换。这些调试功能按钮在画布上方的工具栏里。
(2)Kitchen 和 Pan
作业和转换可以在图形界面里执行,但这只是在开发、测试和调试阶段。在开发完成后,需要部署到实际运行环境中,在部署阶段 Spoon 就很少用到了。部署阶段一般需要通过命令行执行,并把命令行放到 Shell 脚本中,并定时调度这个脚本。Kitchen 和 Pan 命令行工具就是用于这个阶段,在实际的生产环境使用。
Kitchen 和 Pan 工具是 Kettle 的命令行执行程序。实际上,Kitchen 和 Pan 只是在 Kettle 执行引擎上的封装。它们只是解释命令行参数,调用并把这些参数传递给 Kettle 引擎。Kitchen 和 Pan 在概念和用法上都非常相近,这两个命令的参数也基本是一样的。唯一不同的是 Kitchen 用于执行作业,Pan 用于执行转换。在使用命令行执行作业或转换时,需要重点考虑网络传输的性能。Kettle 数据流将数据作为本地行集缓存。如果数据源和目标之间需要通过网络传输大量数据,将 Kettle 部署于源或目标服务器上会极大提升性能。
Kitchen 和 Pan 都通过脚本的方式启动,在 Windows 系统下,脚本名称是 Kitchen.bat 和 Pan.bat,在类 UNIX 系统下,脚本名称是 Kitchen.sh 和 Pan.sh。在执行这些脚本以及 Kettle 自带的其它脚本时,要把 Kettle 目录切换为控制台的当前目录。类 UNIX 系统的脚本默认情况下是不能执行的,必须使用 chmod 命令使脚本可执行。
Kettle 用 Java 语言开发,因此在使用 Kettle 命令行时需要注意匹配 Java 版本。例如 Kettle 8.2.0 版本需要 JDK 1.8 的支持。这样就能在 Spoon 的图形界面下进行设计开发调试,然后用命令行执行保存在本地文件或资源库中的转换或作业,秉承 Java 程序一次编译到处运行的理念。下面是一些命令行的例子。
# 列出所有有效参数
Kettle-home> ./kitchen.sh
# 运行一个存储在文件中的作业
Kettle-home> ./kitchen.sh /file:/home/foo/daily_load.kjb
# 运行一个资源库里的作业
Kettle-home> ./kitchen.sh /rep:pdirepo /user:admin /pass:admin /dir:/ /job:daily_load.kjb
# 运行一个存储在文件中的转换
Kettle-home> ./pan.sh -file:/home/mysql/MongoDB_to_MySQL.ktr
Kitchen 和 Pan 的命令行包含了很多参数,在不使用任何参数的情况下,直接运行 Kitchen 和 Pan 会列出所有参数的帮助信息。参数的语法规范为:
[/-]name [[:=]value]
参数以斜线(/)或横线(-)开头,后面跟参数名。大部分参数名后面都要有参数值。参数名和参数值之间可以是冒号(:)或等号(=),参数值里如果包含空格,参数值必须用单引号(')或双引号(")引起来。
作业和转换的命令行参数非常相似,这两个命令的参数可以分为下面几类:
-
指定作业或转换
-
控制日志
-
指定资源库
-
列出可用资源库和资源库内容
表1-4 列出了 Kitchen 和 Pan 共有的命令行参数。
参数名
|
参数值
|
作用
|
norep
|
|
不连接资源库
|
rep
|
资源库名称
|
要连接的资源库的名称
|
user
|
用户名
|
连接资源库使用的用户名
|
pass
|
密码
|
连接资源库使用的密码
|
listrep
|
|
显示所有的可用资源库
|
dir
|
路径
|
指定资源库路径
|
listdir
|
|
列出资源库的所有路径
|
file
|
文件名
|
指定作业或转换所在的文件名
|
level
|
Error|Nothing|Basic|Detailed|Debug|Rowlevel
|
指定日志级别
|
logfile
|
日志文件名
|
指定要写入的日志文件名
|
version
|
|
显示 Kettle 的版本号、build 日期
|
表1-4 Kitchen 和 Pan 共有的命令行参数
尽管 Kitchen 和 Pan 命令的参数名基本相同,但这两个命令里的 dir 参数和 listdir 参数的含义有一些区别。对 Kitchen 而言,dir 和 listdir 参数列出的是作业的路径,Pan 命令里的这两个参数列出的是转换路径。除了共有的命令行参数外,Kitchen 和 Pan 自己特有的命令行参数分别见表1-5、表1-6。
参数名
|
参数值
|
作用
|
jobs
|
作业名
|
指定资源库里的一个作业名
|
listjobs
|
|
列出资源库里的所有作业
|
表1-5 Kitchen 特有的命令行参数
参数名
|
参数值
|
作用
|
trans
|
转换名
|
指定资源库里的一个转换名
|
listtrans
|
|
表列出资源库里的所有转换
|
表1-6 Pan 特有的命令行参数
(3)Carte
Carte 服务用于执行一个作业,就像 Kitchen 一样。但和 Kitchen 不同的是,Carte 是一个服务,一直在后台运行,而 Kitchen 只是运行完一个作业就退出。当 Carte 在运行时,一直在某个端口监听 HTTP 请求。远程机器客户端给 Carte 发出一个请求,在请求里包含了作业的定义。当 Carte 接到了这样的请求后,它验证请求并执行请求里的作业。Carte 也支持其它几种类型的请求,这些请求用于获取 Carte 的执行进度、监控信息等。
Carte 是 Kettle 集群中一个重要的构建模块。集群可将单个作业或转换分成几部分,在 Carte 服务器所在的多个计算机上并行执行,因此可以分散工作负载。关于 Carte 以及 Kettle 集群的配置和使用,详见本专题的“
Carte 子服务器
”。
8. 虚拟文件系统
灵活而统一的文件处理方式对 ETL 工具来说非常重要,所以 Kettle 支持 URL 形式的文件名。Kettle 使用 Apache 的通用 VFS 作为文件处理接口,替用户解决各种文件处理方面的复杂情况。例如,使用 Apache VFS 可以选中 .zip 压缩包内的多个文件,和在一个本地目录下选择多个文件一样方便。表1-7 里显示的是 VFS 的一些典型的例子。
文件名例子
|
描述
|
文件名:/data/input/customets.dat
|
这是最典型的定义文件的方式。
|
文件名:file:///data/input/customers.dat
|
Apache VFS 可以从本地文件系统中找到文件。
|
作业:http://www.kettle.be/GenerateRows.kjb
|
这个文件可以加载到 Spoon 里,可以使用 Kitchen 执行,可以在作业项里引用。这个文件通过 Web 服务器加载。
|
目录:zip:file:///C:/input/salesdata.zip 通配符:.*\.txt$
|
在“文本文件输入”这样的步骤里可以输入目录和文件通配符。例子里的文件名和通配符的组合将查找 zip 文件里的所有以 .txt 结尾的文件。
|
表1-7 VFS 文件规范的例子
编程和使用工具是常用的开发 ETL 应用的方法,而 ETL 工具又有基于映射和基于引擎之分。面对各种各样的 ETL 开发工具,之所以选择 Kettle 主要归结为下面几点原因。
开发 ETL 系统通常是一个非常复杂的工程,造成这种复杂性的原因很多。数据仓库的数据来源可能分布在不同的数据库,不同的地理位置,不同的应用系统之中,而且由于数据形式的多样性,数据转换的规则大都极为复杂。如果手工编写程序抽取数据并做转换,不可避免地需要大量的设计、编码、测试、维护等工作。这还不包括熟练掌握编程语言的学习成本。另一方面,Kettle 非常容易使用,其所有的功能都通过用户界面完成,不需要任何编码工作。用户只需要告诉它做什么,而不用指示它怎么做,这大大提高了 ETL 过程的开发效率。在 Spoon 界面中,用户通过简单拖拽就能完成绝大部分 ETL 设计工作。
显然多线程并行可以极大提高程序执行效率,然而从编程角度讲,多线程比单线程要考虑的问题多得多。在 Kettle 中设置多线程方式执行非常简单,只要在步骤的右键菜单中选择“改变开始复制的数量”,然后指定线程数即可,其它工作都交给 Kettle 处理,实现细节对用户完全透明。另外再次强调,Kettle 转换中的各个步骤本身就是以数据流的形式并行的。
Kettle 8.3 版本中,转换的核心对象包含输入、输出、应用、转换、脚本等 23 个分类,每个分类中又包含大量的步骤。作业的核心对象包含 14 个分类,同样每个分类中包含大量作业项。数据库连接更是支持 53 种数据库之多。可以说当前 Kettle 原生已经几乎支持所有常见数据源和 ETL 功能需求,而且步骤、作业项、数据库种类还会随着 Kettle 的版本更新而不断增加。
Kettle 是基于 Java 的解决方案,因此天然继承了 Java 跨平台性。用户可以在自己熟悉的环境中(如 Windows、Mac 等),通过图形界面进行 ETL 设计开发,然后将调试好的转换或作业保存为外部 XML 文件,或将元数据存储在资源库中。这样只要有合适的 JVM 存在,转换或作业就能运行在任何环境和平台之上,真正做到与平台无关。
以我个人的经验而言,只要是和关系数据库打交道,很多情况 ETL 通过 SQL 就能搞定。但有时面对看似普通的需求,用 SQL 解决却相当麻烦。在本篇最后举一个实际工作中遇到的简单例子,说明 Kettle 比 SQL 更适合的使用场景,同时加深一点对 Kettle 的直观印象。下一篇文章从安装配置开始进入使用 Kettle 的实操阶段。
收到的需求是这样的:有几百个文本文件,每个文件内容的格式相同,都是有固定分隔符的两列,每个文件有数千行记录。现在需要把这些文件的内容导入一个表中,除了文件内容中的两列,还要存一列记录数据对应的文件名。
向数据库表中导入数据,本来是一件轻而易举的事。可有几百个文件,还要将文件名连同对应的数据一起存入到表中,要手工逐个处理每个文件未免太麻烦了。现在是 Kettle 一显身手的时候了。Kettle 的转换处理数据流,其中有一个“获取文件名”的输入步骤,可以使用它在导入文件数据时添加上文件名字段,而且支持正则表达式同时获取多个文件名,正好适用此场景。下面为在 Kettle 8.3 中的实现步骤。
1. 新建一个转换,包含“获取文件名”、“文本文件输入”、“表输出”三个步骤,如图1-12 所示。
文件所在目录为 Kettle 所在服务器本地的 /tmp/data/,通配符采用正则表达式写法。注意 * 前面要加一个“.”,否则报错。这一步骤会将包括文件名在内的文件的 13 个属性作为输出字段传递给后面的步骤。
3. 设置“文本文件输入”步骤,“文件”、“内容”、“字段”标签分别如图1-14 - 图1-16 所示。
ETL
:
ETL
是用来描述将数据从源端经过提取、
转换
、装入到目的端的过程。
ETL
是
构建
数据仓库的重要
一
环,它包含了三个方面,首先是“抽取”,将数据从各种原始的业务系统中读取出来,这是所有工作的
前
提。其次是“
转换
”,按照预先设计好的规则将抽取的数据进行
转换
,使本来异构的数据格式能统
一
起来。最后是“装载”,将
转换
完的数据按计划增量或全部导入到数据仓库中。
常用
ETL
工具:
ETL
工具的典型代表有Informatica PowerCenter、IBM Datastage、Oracle Warehouse Buil.
ETL
_
Kettle
简介
kettle
是纯 java 开发,开源的
ETL
工具,用于数据库间的数据迁移 。
Kettle
中有两种脚本文件,transformation和job。
transformation
完成
针对数据的基础
转换
,job则
完成
整个工作流的控制.
Kettle
下载地址:
https
:
//sourceforge.net/projects/pentaho/files/Data%20Integration/
Kettle
启动
Kettle
是绿色软件, 解压缩到任意本地路径, 双击Spoon.ba
简介:
Kettle
(Spoon)是Pentaho公司开发的开源
ETL
工具,用于数据整合和数据仓库建设。本学习笔记着重于
Kettle
的核心——
转换
引擎,详细探讨其数据处理的各个步骤,包括数据的输入、
转换
、输出以及工作原理,提供了
一
系列的学习资源和
实践
操作指南,旨在帮助学习者深入理解并掌握
Kettle
的
转换
引擎,从而提升数据处理能力。
Kettle
是
一
款国外开源的
ETL
工具,纯java编写,可以在Window、Linux、Unix上运行,数据抽取高效稳定。
Kettle
中文名称叫水壶,该项目的主程序员MATT 希望把各种数据放到
一
个壶里,然后以
一
种指定的格式流出。
Kettle
这个
ETL
工具集,它允许你管理来自不同数据库的数据,通过提供
一
个图形化的用户环境来描述你想做什么,而不是你想怎么做。
Kettle
中有两种脚...
Kettle
:
简介
ETL
:
简介
ETL
(Extract-Transform-Load的缩写,即数据抽取、
转换
、装载的过程),对于企业或行业应用来说,我们经常会遇到各种数据的处理,
转换
,迁移,所以了解并掌握
一
种
etl
工具的使用,必不可少的,
Kettle
就是强大的
ETL
工具。
Kettle
:
概念
Kettle
是
一
款国外开源的
ETL
工...