简介:本资源为 Kettle 9.3(pdi-ce-9.3.0.0-428)分卷压缩包的第二部分,面向数据工程师、ETL 开发者及需要做数据抽取转换加载的学习者。Kettle 是纯 Java 编写的开源 ETL 工具,绿色免安装,可在 Windows、Linux、Unix 上运行,解压后双击 spoon.bat 即可启动 Spoon 图形界面,通过拖拽方式设计转换与作业流程。压缩包内共约 2000 个文件,以 618 个 jar 依赖库、196 个 ktr 转换脚本、19 个 kjb 作业文件为主,另含 properties、xml、sh、bat 等配置与启动脚本,整体约 799.81MB,因单文件超限而分卷提供,需与资源 1 合并解压。目前已有 876 人学习下载。借助该包可快速搭建本地 ETL 实验环境,研究转换步骤、作业调度与数据库连接配置,适合入门练习与项目排错参考。
1. Kettle 9.3 压缩包到手之后:先别急着双击 Spoon
很多人拿到pdi-ce-9.3.0.0-428这个压缩包的第一反应是解压完直接双击Spoon.bat,然后被一闪而过的黑窗口或者 Java 版本报错劝退。我见过太多同事在这一步卡住,最后得出「Kettle 不好用」的结论。其实 Kettle 9.3 这个版本是 Pentaho Data Integration 社区版里相当稳的一个长期服役版本,压缩包本身就是免安装的绿色形态,解压即用,但前提是你得先把运行环境对齐。它能解决的核心问题很明确:把异构数据源之间的抽取、清洗、转换、加载流程做成可视化作业,不用为每个数据源单独写一套脚本。适合做数仓 ETL、系统间数据同步、批量文件处理的从业者,尤其是那些不想为了一次性数据迁移去搭一整套调度平台的场景。这份资源就是完整的 PDI 社区版压缩包,拿到手之后真正要花心思的是环境配置和驱动补齐,而不是安装本身。
2. 解压后的目录结构与 Java 运行环境对齐
2.1 先认清压缩包里到底有什么
把pdi-ce-9.3.0.0-428.zip解压到一个不含中文和空格的路径下,比如D:\pdi-ce-9.3.0.0-428,你会看到几个关键目录。># Spoon.bat 中手动指定 JAVA_HOME,避免受系统全局 JDK 版本影响 set JAVA_HOME=D:\jdk1.8.0_301 set PATH=%JAVA_HOME%\bin;%PATH% # 下面这行是 Kettle 启动时的 JVM 参数,内存不够时可以调大 -Xmx set PENTAHO_JAVA_HOME=%JAVA_HOME%
这段配置的逻辑是:先锁定JAVA_HOME指向 JDK 8,再把bin目录塞进PATH最前面,保证java命令调用的是这个版本。PENTAHO_JAVA_HOME是 Kettle 自己识别的变量,优先级高于JAVA_HOME,两个都设上最保险。如果你后面处理的数据量比较大,比如单次转换要拉几十万行,可以把默认的-Xmx从 1024m 调到 2048m 或 4096m,具体看机器内存。改完保存,双击Spoon.bat,能看到欢迎界面就说明环境通了。
2.3 验证启动与日志排查
启动过程中如果黑窗口一闪而过,不要反复双击,用命令行进到># 以 MySQL 为例,把驱动复制到 lib 目录后重启 Spoon cp mysql-connector-java-8.0.28.jar D:\pdi-ce-9.3.0.0-428\data-integration\lib\ # 确认文件已就位 dir D:\pdi-ce-9.3.0.0-428\data-integration\lib\mysql-connector-java-8.0.28.jar
复制完不要忘了重启 Spoon,因为 Kettle 是在启动时扫描lib目录加载驱动的,运行中丢进去不会热生效。连接测试的时候,主机名称填 IP 或域名,数据库名称填具体库名,端口号MySQL 默认 3306,用户名和密码按实际填。如果测试报Communications link failure,先检查网络和端口通不通,再检查 MySQL 是否允许远程连接。
3.2 UCanAccess 驱动处理 Access 文件
Kettle 9.3 连接 Access 数据库(.mdb或.accdb)走的是 UCanAccess 方案,这个在热词里被反复提到。UCanAccess 不是一个单独的 jar,而是一组 jar 的集合,包括ucanaccess-x.x.x.jar、jackcess-x.x.x.jar、commons-lang3-x.x.jar、commons-logging-x.x.jar、hsqldb-x.x.x.jar等。你需要把这些 jar 全部放进lib目录,缺一个都会在连接时报ClassNotFoundException。然后在 Spoon 里新建连接时,连接类型选MS Access,访问方式选UCanAccess,数据库文件路径指向你的.accdb文件。
# UCanAccess 依赖包清单,全部放入 lib 目录 # ucanaccess-5.0.1.jar # jackcess-3.0.1.jar # commons-lang3-3.12.0.jar # commons-logging-1.2.jar # hsqldb-2.5.0.jar # 复制完成后重启 Spoon,再测试连接这里有个容易翻车的点:UCanAccess 的版本要和 JDK 版本匹配,5.x 版本要求 JDK 8 以上,如果你用的是 JDK 8 就选 5.0.x,不要选 6.x。另外 Access 文件如果是 64 位 Office 创建的,UCanAccess 读取时偶尔会有编码问题,表现为中文乱码,这时候需要在连接串里加;charSet=UTF-8参数。连接测试通过后,你就可以在转换里用表输入步骤直接查 Access 表了。
3.3 连接池与 JNDI 配置的取舍
开发阶段直接在转换里配数据库连接最省事,但生产环境如果多个转换共用同一个数据源,建议走 JNDI。simple-jndi\jdbc.properties里按名称/type、名称/driver、名称/url、名称/user、名称/password的格式配置,然后在 Spoon 的连接类型里选JNDI,填上你定义的名称即可。这样做的好处是连接信息集中管理,改密码不用逐个转换去改。代价是配置稍微麻烦一点,而且 JNDI 方式下连接池参数调优空间有限。我一般会在开发阶段用直连快速验证逻辑,上线前再统一换成 JNDI。
4. 转换与作业的核心步骤:JavaScript 脚本和参数传递
4.1 JavaScript 步骤的两种模式
Kettle 里的JavaScript 代码步骤是使用频率最高的脚本组件之一,热词里kettle 中javascript代码的搜索量一直不低。这个步骤有两种运行模式:兼容模式和ECMAScript。兼容模式用的是 Rhino 引擎,支持到 ES5,写法偏老但稳定;ECMAScript 模式用的是 Nashorn 引擎(JDK 8 下),支持部分 ES6 语法。如果你只是做字段拼接、条件判断、字符串处理,兼容模式完全够用。写脚本时注意,Kettle 的 JavaScript 步骤里不能直接return,要把结果赋给var声明的变量,然后在步骤的字段列表里把输出字段名填上。
// 兼容模式下做字段清洗和条件映射 // 输入字段:raw_phone, raw_status // 输出字段:clean_phone, status_desc var clean_phone = raw_phone.replace(/[^0-9]/g, ""); if (clean_phone.length === 11) { clean_phone = clean_phone.substring(0, 3) + "****" + clean_phone.substring(7); } var status_desc = ""; if (raw_status == "1") { status_desc = "激活"; } else if (raw_status == "0") { status_desc = "未激活"; } else { status_desc = "未知"; }这段脚本的逻辑是:先用正则把手机号里的非数字字符全部去掉,然后判断长度是否为 11 位,是的话做中间四位脱敏;同时根据raw_status的值映射出中文描述。注意==和===的区别,Kettle 从数据库读出来的字段类型可能是字符串也可能是数字,用==会做隐式类型转换,更不容易翻车。脚本写完后,在步骤的字段列表里把clean_phone和status_desc加进去,类型分别选String,否则下游步骤拿不到这两个字段。
4.2 转换里的参数与变量传递
转换(Transformation)和作业(Job)之间传递参数是 ETL 流程编排的基础。转换里可以通过获取系统信息步骤拿到Internal.Transformation.Filename.Directory等内置变量,也可以通过设置变量步骤把值传给父作业。作业里用转换作业项调用转换时,可以在参数标签页里定义命名参数,转换内部用${参数名}引用。这里有个细节:转换里的表输入步骤如果 SQL 里用了${变量名},必须勾选替换 SQL 语句里的变量,否则变量不会被替换,SQL 会原样发给数据库导致语法错误。
-- 表输入步骤中的 SQL,使用 ${} 引用变量 SELECT id, name, create_time FROM user_info WHERE create_time >= '${start_date}' AND create_time < '${end_date}'这段 SQL 里的${start_date}和${end_date}是作业传进来的参数,格式建议统一用yyyy-MM-dd。勾选变量替换后,Kettle 会在执行前把变量值拼进 SQL。注意日期字段如果是datetime类型,用字符串比较在 MySQL 里没问题,但在 Oracle 里可能隐式转换失败,稳妥做法是用TO_DATE('${start_date}', 'YYYY-MM-DD')。参数传递的链路是:作业里定义参数 → 转换作业项里赋值 → 转换内部引用,任何一环名字写错都会导致变量为空,SQL 变成WHERE create_time >= '',结果要么报错要么查出全表。
4.3 作业调度与 Kitchen 命令行执行
开发调试用 Spoon 图形界面,生产跑批用Kitchen.bat命令行。基本用法是Kitchen.bat /file:作业路径 /level:Basic,/level控制日志级别,可选Basic、Detailed、Debug、Rowlevel。Rowlevel会打印每一行数据,调试时用,生产环境千万别开,日志能把磁盘撑爆。如果作业里用了参数,命令行通过/param:名称=值传入。跑批结束后,Kitchen 的退出码 0 表示成功,非 0 表示失败,调度平台可以根据退出码判断是否告警。
# Linux 下用 Kitchen 执行作业,传入日期参数 ./kitchen.sh /file:/data/etl/job_daily.kjb /level:Basic /param:start_date=2024-01-01 /param:end_date=2024-01-02 # 检查退出码 echo $?这段命令的逻辑是:指定作业文件路径,日志级别设为 Basic,传入两个日期参数。echo $?拿到上一条命令的退出码,0 就是成功。注意 Linux 下kitchen.sh需要有执行权限,chmod +x kitchen.sh先加上。另外KETTLE_HOME环境变量如果没设,Kettle 会默认用当前目录下的.kettle文件夹存配置,生产环境建议显式设置KETTLE_HOME到一个固定路径,避免不同用户跑批时配置不一致。
5. 避坑与排查:那些让你加班到凌晨的常见问题
5.1 中文乱码:现象是数据入库后变成问号
现象:从 CSV 或 Excel 读取的中文字段,经过转换写入数据库后变成???或者乱码。原因:源文件编码和 Kettle 读取时指定的编码不一致,或者数据库连接串没指定字符集。解决:在CSV 文件输入步骤里把编码显式设为UTF-8或GBK,在数据库连接的高级选项里加上characterEncoding=utf8。如果是 Access 文件,UCanAccess 连接串加;charSet=UTF-8。
5.2 内存溢出:现象是跑大表时 Spoon 卡死或报 OutOfMemoryError
现象:转换处理几十万行数据时,Spoon 界面无响应,日志里出现java.lang.OutOfMemoryError: Java heap space。原因:JVM 默认堆内存太小,或者转换里用了排序记录、分组这类需要全量缓存的步骤。解决:调大Spoon.bat里的-Xmx参数到 4096m 或更高;同时检查转换逻辑,能流式处理的不要用全量排序,排序记录步骤可以勾选缓存大小并配合临时文件选项,让 Kettle 把中间结果溢写到磁盘而不是全放内存。
5.3 驱动冲突:现象是同一个 lib 目录放了多个版本的驱动
现象:连接数据库时报No suitable driver found或者ClassCastException。原因:lib目录下同时存在同一个数据库的多个版本驱动 jar,Kettle 加载时顺序不确定,可能加载了旧版本。解决:清理lib目录,同一个数据库只保留一个版本的驱动。MySQL 的mysql-connector-java尤其容易出这个问题,因为很多其他工具也会往环境里丢这个 jar。定期用dir lib\*mysql*检查一下。
5.4 变量未替换:现象是 SQL 里${}原样发给数据库
现象:表输入步骤的 SQL 里写了${start_date},执行时报语法错误,日志里能看到 SQL 里还是${start_date}。原因:没有勾选替换 SQL 语句里的变量,或者变量名拼写和上游定义的不一致。解决:勾选该选项;在转换里加一个写日志步骤,把变量值打印出来确认;检查作业里传参时的名称是否和转换里引用的一致,大小写敏感。
5.5 作业并发冲突:现象是定时任务重叠执行导致数据重复
现象:上一个作业还没跑完,下一个调度周期又启动了同一个作业,同一批数据被处理两次。原因:调度平台没有做互斥控制,或者 Kettle 作业本身没有加锁机制。解决:在作业开头加一个检查文件是否存在或者检查数据库标志位的步骤,如果上一次还没结束就直接跳过本次执行;或者在调度平台层面配置同一作业串行执行。Kettle 本身不提供作业级别的分布式锁,这个得靠外部调度系统兜底。
6. 进阶技巧:用 Carte 做远程执行与日志集中管理
Carte 是 Kettle 自带的轻量级 Web 服务,很多人下载完压缩包只用了 Spoon 和 Kitchen,完全忽略了Carte.bat。它的价值在于:你可以把转换和作业部署到一台专门的 ETL 服务器上,通过 Carte 的 REST 接口触发执行,Spoon 只作为设计器不承担运行压力。启动 Carte 的命令是Carte.bat 8080,8080 是监听端口,启动后访问http://IP:8080能看到一个简单的管理页面。然后在 Spoon 里配置子服务器,填上 Carte 的地址和端口,就可以把转换远程提交上去跑。
# 启动 Carte 服务,指定端口和日志目录 ./carte.sh 0.0.0.0 8080 # 后台运行并输出日志到文件 nohup ./carte.sh 0.0.0.0 8080 > carte.log 2>&1 &这段命令的逻辑是:0.0.0.0表示监听所有网卡,8080是端口,nohup加&让服务在后台跑,日志重定向到carte.log。启动后,Carte 的日志里会记录每一次远程执行的转换名称、开始时间、结束时间、处理行数。你可以用tail -f carte.log实时看执行情况。生产环境建议把 Carte 注册成系统服务,用systemd或者supervisord管理,避免进程意外退出后没人拉起来。
远程执行的另一个好处是日志集中。所有转换的日志都落在 Carte 所在服务器的日志文件里,不用去每台机器上翻 Spoon 的本地日志。如果你在转换里加了写日志步骤,日志内容也会一并输出到 Carte 的日志流里。我一般会在每个转换的末尾加一个写日志步骤,把处理行数、耗时、关键参数打印出来,这样排查问题时直接 grep 日志文件就行,不用重新跑一遍转换。
还有一个容易被忽略的技巧:Carte 支持通过 REST 接口动态传参。你可以用curl发一个 POST 请求,把参数以 JSON 格式传进去,触发指定的转换或作业。这样就能和外部调度系统(比如 Airflow、DolphinScheduler)集成,由调度系统负责编排和依赖管理,Kettle 只负责单次执行。接口地址格式是http://IP:8080/kettle/runTrans/?trans=转换路径¶m=值,具体参数名和转换里定义的命名参数对应。
从那以后我每次部署 Kettle 到新环境,都强制走一遍「JDK 版本确认 → lib 驱动清理 → Carte 服务注册 → 日志目录挂载」这四步,少一步后面都可能出玄学问题。希望帮到你。
本文还有配套的精品资源,点击获取