最近在用kettle迁移数据,从对kettle一点不会到比较熟悉,对于期间的一些问题和坑做了记录和总结,内容涵盖了使用的经验和技巧,踩到的坑、最佳实践和优化前后结果对比。
常用转换组件
- 计算形成新字段:只限算术运算,并且选择固定
- 过滤记录:元表某字段按照某个条件分流,满足条件的到一个表,不满足的到另一个表,这两个目标表都必须有。
- Switch/Case:和过滤记录类似,可以多个条件判断,并且有默认转向条件,可以完美替换过滤记录组建
- 记录分组:group by 组建未能正常按照预期理解运行
- 设置为NULL:将某个特定值设置为NULL
- 行扁平化:行扁平化,使用与某条件下某名称对应的行数相同的情况
- 行列转换:行转成列,使用Row Normalizer组件,事先一定要是根据分组字段排好序,关键字段就是name列字段,分组字段就是按照什么分组,目标字段就是行转列之后形成的字段列表。 8.字段选择:选择需要的目的列到目标表,并且量表的对应字段不一样时可以用来做字段映射
- 排序:分组前先排序可以提高效率
- 条件分发:根据条件分发,相当与informatica的router组件
- 值映射:相当与oracle的decode函数,源和目标字段同名的话,只要写源字段就可以了
#常用输入组件
- 表输入:源表输入
- 文本文件输入:文本文件输入
- xml文件输入:使用Get Data From XML组件,可以在其中使用xpath来选择数据
- JsonInput:貌似在中文环境下组件面板里看不到,切换到英文模式就看到了
#常用输出组件
- 表输出:表输出
- 文本文件输出:文本文件输出
- XML文件输出:输出的XML文件是按照记录行存储的,字段名为元素名
- Excel文件输出:输出的excel文件是按照记录行存储的,字段名为元素名
- 删除:符合比较条件的记录将删除
- 更新:注意两个表都要有主键才可以
- 插入/更新:速度太慢,不建议使用
- 检查字段是否存在:若在则家一个标志位,值可以是Y/N
- 等值连接:有关联关系字段可以关联,其它的不关联。
- 笛卡尔连接:所有两边的记录交叉连接
- write to log:把数据输出到控制台日志里,一般调试时很常用
- 空操作:很常用,比如过滤数据,未过滤走正常流程,滤除的数据就转向空操作。我喜欢在转换里用它做开始和结束之类需要分发或汇聚数据流的场景
#内置变量
Internal.Transformation.Name 当前转换的名字
Internal.Job.Name 当前job名字
Internal.Job.Filename.Name job的文件名
#需要修改的配置
在java8里-XX:MaxPermSize,-XX:PermSize已经去掉了,需要修改成-XX:MetaspaceSize 和 -XX:MaxMetaspaceSize
生产环境和开发环境使用不同的数据库连接
~/.kettle/kettle.properties里设置key=value
在kettle.properties中添加变量,然后在类似数据库连接的地方可以用${key}来使用,这样可以实现开发环境和生产环境配置的差异,就算往资源库里提交也可以互不影响了
kettle分页问题
kettle循环分页
首先弄一个转换A,根据源表获取记录数,页数,每页记录数,然后写入系统变量,然后在job里调用转换A,再加一个转换B来迁移数据(其中查询sql要使用转换A生成的系统变量),最后在job里用一个javascript脚本来判断查询记录数是否是0,如果是0就走执行成功,否则就继续执行转换B。
最关键的是判断的js脚本,可以参考
var prevRow=previous_result.getRows();//获取上一个传递的结果,这种方案需要在转换B中将记录集复制为结果,如果记录集较多会造成内存溢出。就算在job里执行也是如此
完整代码:
if (prevRow==null && prevRow.size()==0){
false;
}else{
var startRow=parseInt(parent_job.getVariable("START_ROW", 0));
var pageSize=parseInt(parent_job.getVariable("PAGE_SIZE",1000));
startRow=startRow+pageSize;
parent_job.setVariable("START_ROW", startRow);
true;
}
kettle分页循环的更高效的改进方案
在转换里,每执行一次有个SUCC_COUNT环境变量就+1,在job中用js脚本判断成功数是否>=总记录数,是就终止循环,否就起始行+每页记录数,下面是代码
var startRow=parseInt(parent_job.getVariable("startrow"));
var totalItemCount=parseInt(parent_job.getVariable("totalitemcount"));
if (startRow >= totalItemCount){
false;
}else{
true;
}
对比前一种方案,改进方案一次迁移一万条数据没有压力&#