【IT168 技术文档】
摘要:本文主要讨论使用Kettle来设计一些较为复杂和动态的转换可能使用到的一些技巧,这些技巧可能会让你在使用Kettle的时候更加容易的设计更强大的ETL任务。
动态参数的传递
Kettle 在处理运行时输入参数可以使用JavaScript 来实现,大部分工作只是按照一个模板来处理的
动态参数传递主要使用在像数据清理,调式,测试,完成复杂的条件过滤等等,这种方式一般不会在产品已经运行稳定了一段时间之后使用,因为我们一般仍然是做定时任务来自动转换数据,所以在开始介绍如何使用动态参数之前,希望大家能明白不要在产品数据库上做实验,即使你已经知道你的转换有什么影响并且做了备份,因为这种方法是不可能自动执行的。
Kettle有两种动态参数传递的方法,一种是非常轻量级的传argument , 另一种是对付较复杂一点情况使用JavaScript . 下面分别介绍这两种方法。
1. argument
当你在运行一个转换的时候,不管这个转换是一个Job的一部分还是只有这个转换,你都可以传递参数给它,当你运行一个转换的时候,会弹出一个Execution a Transformation 的对话框,让你选择执行转换的方式,本地执行,远程执行,分布式执行,下面就是日志记录的级别和回放时间,然后是argument 和 variables 的设定。Argument 和 variables 的区别在官方FAQ里面也有解释。你也可以参考一下官方的解释和下面解释的异同。
Q : Argument 和 variables 的区别 /
A : variables 也可以认为叫做environment variables , 就像它的名字一样,主要是用来设定环境变量的,比如最常见的:文件的存放地址,smtp的配置等等,你也可以把它认为是编程语言里面的全局变量,即使是不同的转换它们也拥有同样的值,而argument 自然就类似与局部变量,只针对一个特定的转换,比如像是限定结果集的大小和过滤条件。
取得argument的值
我们在转换之前设置了argument的值,需要用到的时候就使用get system info 步骤,这个步骤取得在运行时参数,需要注意的是我们是先设置get system info ,然后在里面决定要使用多少个参数,最多10个,每个参数名叫什么,然后我们才能在运行时看到你设置了的参数名后面跟一个要你输入的值,并且参数类型是不能够指定,全部都当作字符串处理,如果你需要对参数类型有要求,你需要自己转换,使用一个Mapping步骤或者Select values步骤。
取得variable的值
Variable的值个数不受限制,你可以在kettle菜单的set environment里面设置,也可以使用文件储存这些值,在第一次运行kettle之后,kettle会在%HOME_USER_FOLDER%菜单里面创建一个 .kettle文件夹,如果是windows 用户可能就是C:\Documents and Settings\${your user name}\.kettle这个文件夹,如果是linux用户可能就是/home/${your user name }/.kettle文件夹,这个文件夹下面有kettle.properties文件,如果你打开这个文件,你会发现里面有一些以#开头的注释,其中设置了一些像是:PRODUCTION_SERVER = Hercules 这样的键值对,你可以自己定义一些环境变量比如像是smtp的地址,ftp服务器的地址,你放log文件的目录名等等,当然不能直接编辑这个文件就设置环境变量,要先设置KETTLE_HOME环境变量,windows就是点我的电脑,然后在设置path的那个地方添加一个KETTLE_HOME变量,linux就是export KETTLE_HOME=’一个目录’,这个目录可以任意地方,不过一般还是指向kettle的安装目录或是你自己的文档目录,然后启动kettle它会创建一个新的.kettle目录,编辑里面的kettle.properties文件就可以设置环境变量了.
2. 使用脚本
Kettle使用的是JavaScript来作为它的脚本实现,使用的是mozilla 的rhino 1.5r5版本实现,如果你打算实现一些复杂的计算过程,比如字符串分割,数据类型转换,条件计算等等,你都应该使用脚本语言来搞定。
我们在某种应用环境下使用脚本语言来实现一些动态的功能大部分原因都是为了避免编程,一个复杂一点的应用程序,比如像是Kettle这种工具,或是报表工具,它们不可能提供全部功能,把什么都做成图形化,应用条件永远都是复杂的,如果你不想研究代码和程序的结构,甚至你都不知道怎样编程,脚本语言绝对是一种简单的解决方案,而JavaScript语言又是其中入门门槛非常低的一种,你完全可以多看一些例子,尝试模仿一些脚本来解决问题,也许会有一点难以调试和测试,但总比自己编程要好的多。
下面的这个例子将会使用JavaScript弹出一个对话框来接受两个参数,都是时间类型,其中的UI组件是使用的swt 的一些类,Kettle使用的是swt 作为其UI组件,如果你对swt 有了解的话会更容易理解这些UI组件,当然这并不需要你有swt 编程的经验或者其他GUI设计的经验。
打开Kettle 下载目录下的samples / transformation / JavaScript dialog.ktr 文件(使用Kettle File 菜单里面的import from an xml file 。你会看到一个包含3个步骤的转换。
第一个步骤使用generate rows 产生一条测试数据,测试数据包含一个DateFromProposal 时间字段和一个DateToProposal时间字段。
第二个步骤使用JavaScript 来实现动态的参数转变,它会连续弹出两次对话框,要求输入一个起始值和结束值,然后它会调用一些JavaScript 函数来对日期格式做一些处理,
第三个步骤使用Dummy 来接受输入,你完全可以使用File output 步骤来查看输出。
我们先看一下第二部中的JavaScript代码:(删掉了开头的注释)
var display;
var displayHasToBeDisposed=false;
var shell=null;
try {
display=Packages.org.eclipse.swt.widgets.Display.getCurrent();
shell=display.getActiveShell();
} catch(e) {
// if it runs in batch mode (Pan or preview mode) no Display is available, so we have to create one
display=new Packages.org.eclipse.swt.widgets.Display();
displayHasToBeDisposed=true;
shell=new Packages.org.eclipse.swt.widgets.Shell(display);
}
// if we run in Pan we need to load the properties:
if(!Packages.org.pentaho.di.ui.core.PropsUI.isInitialized()) {
Packages.org.pentaho.di.ui.core.PropsUI.init(display,2); //2=TYPE_PROPERTIES_PAN
}
var dateDefaultFrom=DateFromProposal.getString().substr(0,10); //only the date and not the time
var dialogDateFrom=new Packages.org.pentaho.di.ui.core.dialog.EnterTextDialog(shell, "Date from", "Please enter the beginning date", dateDefaultFrom);
var dateFromAsString=dialogDateFrom.open();
if(dateFromAsString!=null && dateFromAsString.length()>0) {
var dateDefaultTo=DateToProposal.getString().substr(0,10); //only the date and not the time;
var dialogDateTo=new Packages.org.pentaho.di.ui.core.dialog.EnterTextDialog(shell, "Date to", "Please enter the ending date", dateDefaultTo);
var dateToAsString=dialogDateTo.open();
if(dateToAsString!=null && dateToAsString.length()>0) {
// here you could check or change formats a.s.o
} else {
// stop transformation when user cancels
throw new Packages.java.lang.RuntimeException("Input canceled by the user.");
}
} else {
// stop transformation when user cancels
throw new Packages.java.lang.RuntimeException("Input canceled by the user.");
}
if(displayHasToBeDisposed) {
display.dispose();
}
Display 和 shell 都是swt 里面的对象,你只用知道他们是表示UI的就可以了.
DateFromProposal和DateToProposal都是前面传过来的字段,dateFromAsString和dateToAsString都是需要输出的内容,整个脚本只是简单的取了两个日期变量的时间部分,使用了字符串操作的substr()函数。
其中有三点需要注意:
1. dialog对象的初始化方式:使用的构造函数类型为
EnterTextDialog(Shell parent, String title, String message, String text) , 另一种构造函数类型是加一个参数fixed :
EnterTextDialog(Shell parent, String title, String message, String text, boolean fixed)
fixed代表字体是否用固定宽度,text参数代表的是输入在对话框里面的值,一般可以默认为空或输入一段用户提示信息,例子中是设置成原先转换之前的值,相当于默认值。
2. 使用open()函数取得输入值
我们调用dialog 的open()函数取得输入的值。
3. 异常的处理方式
基本上是一个标准的java 语法的try catch throw .
最后运行一下并查看输出,运行的时候什么都不输入接受默认值就可以了,最后查看输出,以下是文本方式的输出,以分号分割
DateFromProposal;DateToProposal;dateFromAsString;dateToAsString
2006/01/01 00:00:00.000;2006/12/31 00:00:00.000;2006/01/01;2006/12/31
最后需要注意的是这种方式的实现可能将来会直接用一个新的step来实现,不用这样写脚本。
调试
调试可不是程序的专利,ETL过程同样需要调试过程,Kettle同样支持比较简单的调试过程,你可能已经发现了在菜单下面的工具栏下面有一个debug 和preview 按钮来支持调试过程,这种调试的技巧同样可以用来帮助你完成一些复杂的ETL工程,下面以一个例子来解释调试过程.
首先,打开samples / add sequence specify a common counter.ktr 文件,你会发现一个定义了两个sequence 的转换,点击debug按钮,它会弹出一个Transformation debug dialog 窗口。
图1
这个窗口左边列出了在这个转换中所有的步骤,我们选取Generate ID 步骤,然后设置断点的条件:
Kettle支持两种断点的方法,一种基于限定结果集的数量大小,另一种是基于条件的判断过程。
我们选择基于结果集大小的方式,只查看前面5条数据。
你会看到Kettle列出了Generate ID 步骤产生的前面5条数据,
图2
从上图中可以看到这个generate id 步骤产生了5个值并不是连续的,下面的按钮Close ,Stop 可以控制当前线程是继续还是停止.
利用调试的方法可以帮住我们设计一些需要基于条件判断的复杂ETL过程,我们使用调试的方法来查看数据中是否可能存在某些特定数据,以此来设计一些ETL过程针对这些数据进行处理。
相关文章:
开源ETL工具kettle系列之建立缓慢增长维
http://tech.cms.it168.com/db/2008-03-21/200803211716994.shtml
开源ETL工具kettle系列之动态转换
http://tech.cms.it168.com/o/2008-03-17/200803171550713.shtml
开源ETL工具kettle系列之增量更新设计技巧
http://tech.cms.it168.com/db/2008-03-21/200803211924754.shtml
开源ETL工具kettle系列之在应用程序中集成
http://tech.it168.com/db/2008-03-19/200803191510476.shtml
开源ETL工具kettle系列之常见问题
http://tech.it168.com/db/2008-03-19/200803191501671.shtml