ETL工具 Kettle 中怎么通过变量传参

ETL工具 Kettle 中怎么通过变量传参 第一章 Kettle参数体系概述在深入学习具体操作之前有必要先理清Kettle中几个容易混淆的核心概念变量Variable、参数Parameter或Argument以及它们各自的作用域。理解这些是正确传参的基础。1.1 为什么需要变量传参假设你有一个每天凌晨运行的作业需要抽取前一天的数据。如果没有变量你每天都需要手动修改SQL中的日期或者为每一天创建一个单独的转换这显然是不可行的。变量的引入使得ETL流程具备了动态性和可配置性。环境隔离通过变量区分开发库、测试库和生产库的连接信息迁移作业时无需修改作业本身 。业务驱动根据调度系统传入的不同日期动态计算数据范围 。逻辑复用同一个转换可以通过传入不同的参数实现不同的过滤逻辑。1.2 变量Variable与参数Parameter的区别很多初学者容易混淆这两个术语虽然在实际使用中它们经常互换但在Kettle的语境下有明确的区分 。特性变量 (Variable)命名参数 (Parameter)位置参数 (Argument)作用域全局JVM级别或局部Job/Trans仅限定义它的转换或作业仅限定义它的转换定义方式kettle.propertiesSet Variables步骤转换/作业的属性对话框中定义使用Get System Info步骤定义传递方式系统环境变量或通过步骤设置运行时通过对话框或命令行传入运行时按顺序第1个第2个...传入数量限制无限制无限制最多10个适用场景数据库连接、文件根目录等全局配置业务日期、表名等运行时必须传入的值简单的、顺序敏感的少量参数通俗理解变量Variable就像是操作系统的环境变量一旦设定处处可用当然也有局部变量。通常存放不变或极少变动的配置。命名参数Parameter就像是函数的具名参数调用时必须指定参数名可读性好顺序可换。位置参数Argument就像是函数的顺序参数通过arg0, arg1...访问简单直接。1.3 参数的作用域与优先级Kettle中变量存在覆盖机制优先级由高到低通常为命令行传入的命名参数/变量最高优先级。在作业或转换中通过“Set Variables”步骤设置的变量作用于当前作业/转换或其子作业。在作业或转换的属性中定义的命名参数。kettle.properties中定义的全局变量。系统环境变量或启动脚本中设置的变量。理解这一点非常重要如果你在kettle.properties中定义了一个变量又在命令行中传入了同名的参数命令行传入的值会覆盖配置文件中的值。第二章 全局变量kettle.properties的配置与使用全局变量是Kettle中最基础的变量形式。它们存储在文件中对所有作业和转换可见。2.1 配置文件位置kettle.properties文件位于用户目录下的.kettle隐藏文件夹中。具体路径取决于操作系统 WindowsC:\Users\你的用户名\.kettle\kettle.propertiesLinux / Mac~/.kettle/kettle.properties如果该文件不存在可以手动创建或者在首次打开KettleSpoon时自动生成。2.2 定义全局变量使用任意文本编辑器打开该文件按照键值的格式添加变量。properties# 数据库连接配置 PG_HOST192.168.1.100 PG_PORT5432 PG_DBNAMEedw PG_USERetl_user PG_PASSWORDEncrypted 2be98afc86aa7f2e4cb79ce10be483fd8a # 文件路径配置 ETL_DATA_ROOTD:/data/etl/input ARCHIVE_PATHD:/data/etl/archive # 业务参数 DEFAULT_START_DATE2023-01-01关于密码加密如示例所示你可以在命令行中使用Kettle自带的encr.sh或encr.bat工具对密码进行加密然后以Encrypted 密文的形式存储在配置文件中避免明文密码暴露 。2.3 在转换和作业中引用全局变量配置完成后需要重启Spoon GUI工具才能生效。在转换或作业中可以通过${变量名}或%%变量名%%两种方式引用 。示例在“表输入”步骤中使用全局变量假设你的SQL通常写成固定IP现在可以改写成sqlSELECT user_id, user_name, create_date FROM source_schema.user_table WHERE create_date ${DEFAULT_START_DATE}关键操作在“表输入”步骤中必须勾选“替换SQL语句里的变量”复选框否则${DEFAULT_START_DATE}会被当作普通字符串传给数据库导致SQL执行失败 。2.4 全局变量的优点与局限优点一处定义全局可用非常适合管理数据库连接、FTP地址、根目录等固定配置。局限修改后必须重启Spoon或在命令行中重启JVM才能重新加载不适合需要频繁变化的参数如每日日期。第三章 命名参数Parameter转换/作业的“接口”命名参数是Kettle 3.2以后引入的更规范化的参数传递方式。它要求你必须预先定义参数的“接口”然后才能传入值 。3.1 在转换中定义命名参数在Spoon中打开一个转换。点击画布空白处或在主菜单栏选择“转换” - “设置” 或使用快捷键Ctrl Shift W。在弹出的“转换属性”窗口中选择“参数”选项卡。点击“获取参数”或手动添加。定义参数的“参数名称”如REPORT_DATE和“默认值”如2023-01-01。建议勾选“设置为系统变量”这样该参数在转换中可以直接像变量一样被引用 。3.2 在命名参数与“获取变量”步骤结合使用定义好命名参数后通常配合“获取变量”Get Variables步骤将其转换为字段流供后续步骤使用。操作步骤在转换中添加一个“获取变量”步骤。双击步骤进行配置。在“字段”表格中名称给传入的变量起一个字段名例如reportDateField。变量输入${REPORT_DATE}即你在转换属性中定义的参数名。类型选择合适的数据类型如 Date如果期望是日期类型。格式如果类型是Date需要指定格式如yyyy-MM-dd。这样reportDateField就成为了数据流中的一个字段可以被“表输入”等步骤通过字段名而不是变量语法引用。3.3 在作业中执行时传递命名参数当你在作业中调用这个包含命名参数的转换时可以为其赋值在作业画布中添加一个“转换”作业项。双击该作业项选择要运行的转换。切换到“参数”选项卡。你会看到转换中定义的所有命名参数列表。在“值”列中你可以直接输入固定值也可以通过${作业级变量}来动态赋值。3.4 命令行传递命名参数这是调度系统如Azkaban、Airflow、Crontab调用Kettle任务的标准方式。对于转换.ktr使用pan.shLinux或pan.batWindows。对于作业.kjb使用kitchen.sh或kitchen.bat。语法-param:参数名参数值。示例通过Kitchen向作业传递参数bash# Linux / Mac ./kitchen.sh -file/home/etl/jobs/daily_load.kjb \ -param:REPORT_DATE2023-10-26 \ -param:LOAD_TYPEFULL \ -level:Basic /home/etl/logs/daily_load.log # Windows kitchen.bat -fileD:\etl\jobs\daily_load.kjb ^ -param:REPORT_DATE2023-10-26 ^ -param:LOAD_TYPEFULL ^ -level:Basic-level参数用于指定日志级别生产环境通常使用Basic以减少IO开销 。第四章 位置参数Argument最传统的传参方式位置参数是Kettle早期版本就支持的方式通过arg0, arg1, ..., arg9来访问 。4.1 通过“获取系统信息”步骤接收参数在转换中拖入一个“获取系统信息”Get System Info步骤。这通常是转换的第一个步骤。双击配置在“字段”表格中添加行。名称为参数起一个字段名如startDateArg。类型选择“系统信息类型”为arg0到arg9中的某一个。格式根据需要指定。示例配置一行名称为start_date类型为arg 0这意味着它会接收运行时传入的第一个参数。4.2 引用与使用该步骤运行后会输出一个包含start_date字段的单行数据流。你可以将这个字段通过“字段选择”或直接连接到“表输入”等步骤使用。如果要在SQL中直接引用原始的参数值而不是经过字段转换依然可以使用${arg0}的变量语法但这不推荐因为“获取系统信息”步骤能提供更好的数据类型转换。4.3 命令行传递位置参数位置参数的传递更简单直接在命令后面按顺序添加即可。bashpan.sh -file/home/etl/trans/load_table.ktr \ -param:REPORT_DATE2023-01-01 \ -param:REPORT_DATE2023-01-01 \ /home/etl/trans/load_table.ktr 2023-10-26 FULL在上述命令中2023-10-26将成为arg0FULL将成为arg1。第五章 变量步骤间的传递Set Variables 与 Get Variables有时候你需要在同一个作业或转换的执行过程中动态生成变量并供后续步骤使用。这时就需要用到“设置变量”Set Variables和“获取变量”Get Variables步骤。5.1 “设置变量”步骤将字段值保存为变量假设你有一个需求先从一个表中读取当前最大日期然后将这个日期作为变量供后面的数据抽取使用 。操作步骤读取值使用“表输入”或“获取系统信息”步骤获取到具体的值比如日期2023-10-26并输出一个字段比如名为max_date。设置变量拖入一个“设置变量”Set Variables步骤连接到上一步。配置在“字段名称”列选择输入的字段名max_date。在“变量名称”列定义要设置的变量名例如VAR_MAX_DATE。变量活动类型重要Valid in the Java Virtual Machine设置为JVM级别变量在整个JVM实例中都有效对其他独立运行的转换也可见作用范围最广但需谨慎使用。Valid in the parent job设置为父作业变量。当前组件如果是作业中的一个子转换设置后其父作业可以引用该变量。Valid in the grand-parent job设置为祖父作业变量。Valid in the root job设置为根作业变量。注意事项“设置变量”步骤设置的变量不能立即在同一个转换中被“获取变量”步骤获取到。它必须在当前转换结束进入下一个转换或作业的后续步骤时才能生效 。这是Kettle执行流中一个非常关键的特性。5.2 “获取变量”步骤将变量引入数据流这个步骤在3.2节中已经介绍过它是将现有的变量无论是全局变量、命名参数还是通过“设置变量”生成的变量转换成数据流中的字段。典型组合在作业中先执行一个“转换A”来“设置变量”然后再执行一个“转换B”来“获取变量”并使用它 。5.3 案例作业内动态参数传递实战需求抽取昨天的数据装载到目标表中 。设计思路需要一个作业包含两个转换Set_Param.ktr计算并设置昨天日期变量和Extract_Data.ktr使用该变量抽取数据。Step 1: 创建“设置参数”转换 (Set_Param.ktr)获取系统信息拖入“获取系统信息”步骤获取“昨天 00:00:00”的日期系统信息类型选择“yesterday start”。字段选择将上一步输出的日期格式化为你需要的格式如yyyy-MM-dd字段名改为yesterday_str。设置变量连接“设置变量”步骤。将yesterday_str设置为变量变量名定义为YESTERDAY。活动类型选择“Valid in the root job”或“Valid in the parent job”。Step 2: 创建“数据抽取”转换 (Extract_Data.ktr)表输入编写SQL使用${YESTERDAY}作为过滤条件。切记勾选“替换SQL语句里的变量”。Step 3: 创建作业串联新建一个作业。先添加一个“转换”作业项选择Set_Param.ktr。再添加一个“转换”作业项选择Extract_Data.ktr。用作业连接线将两个作业项连接起来。运行这个作业第一个转换计算出日期并设置为变量第二个转换成功引用该变量完成动态抽取。第六章 跨作业与跨转换的参数传递在实际复杂的ETL项目中通常是一个顶层Job主控作业调用多个子Job和子Transformation。参数如何在它们之间顺畅传递是核心问题。6.1 从顶层作业向子作业传递这是最常见的场景。顶层Job接收调度系统传来的业务日期然后分发给各个子模块。定义在顶层Job的属性中定义命名参数如PARAM_DATE。调用在顶层Job中添加一个“作业”作业项即子作业。传递双击子作业项进入其配置界面找到“参数”选项卡。在这里你会看到子作业自身定义的参数列表。在“值”列中填入${PARAM_DATE}即引用顶层Job的参数。Kettle会自动完成变量的映射和传递 。关键点子作业必须事先定义好它需要接受的参数在其作业属性中。即使顶层Job有同名变量如果子作业没有定义接收参数也无法直接使用。6.2 从作业向转换传递与向子作业传递类似。在作业中添加“转换”作业项。双击配置进入“参数”选项卡。将作业中的变量如${JOB_VAR_DATE}映射给转换定义好的命名参数如TRANS_PARAM_DATE。6.3 JavaScript脚本中的变量传递Kettle支持在“JavaScript代码”步骤中直接操作变量和字段这为实现复杂逻辑提供了极大便利 。6.3.1 读取变量和字段读取字段值如果输入流中有字段field1在JavaScript中可以直接通过field1大小写敏感获取其值。读取变量值使用getVariable(变量名, 默认值)函数。6.3.2 设置变量和字段设置字段值直接对字段赋值如field1 field1.trim();如果要对不存在于输入流中的字段赋值需要在JavaScript步骤的“字段”选项卡中预先定义输出字段的名称和类型。设置变量值使用setVariable(变量名, 新值)函数。需要注意的是通过setVariable设置的变量其作用范围取决于该步骤的配置类似于“设置变量”步骤同样不能在同一次转换中立即读取 。6.3.3 案例JavaScript弹窗接收参数这是一个非常古老的技巧主要用于设计期的调试或临时性的手动数据清理任务。它利用Kettle的UI库SWT弹出对话框接收用户输入 。javascript// 获取当前显示对象用于弹窗 var display Packages.org.eclipse.swt.widgets.Display.getCurrent(); var shell display.getActiveShell(); // 创建日期输入对话框 var dialog new Packages.org.pentaho.di.ui.core.dialog.EnterTextDialog(shell, 请输入日期, // 对话框标题 请输入要抽取的日期 (YYYY-MM-DD):, // 提示信息 getVariable(DEFAULT_DATE, 2023-01-01) // 默认值从变量获取 ); var userInput dialog.open(); if (userInput) { // 将用户输入设置成变量供后续使用 setVariable(USER_DATE, userInput); } else { // 用户取消抛出异常停止执行 throw new Packages.java.lang.RuntimeException(用户取消了输入); }注意这种代码只能在Spoon GUI环境中运行如果通过命令行Pan/Kitchen执行会因为无法创建图形界面而报错。第七章 命令行与脚本传参实现全自动化生产环境中的Kettle任务通常由自动化调度工具触发必须通过命令行传递所有必要的参数。7.1 Kitchen与Pan命令详解Kitchen用于执行作业.kjb文件。Pan用于执行转换.ktr文件。常用参数-file: 指定要执行的作业或转换文件路径。-param:: 设置命名参数的值推荐方式。-level: 设置日志级别ErrorWarnBasicDetailedDebugRowLevel。-logfile: 指定日志输出文件。7.2 在Shell/Bat脚本中封装调用为了管理复杂的参数通常会编写Shell脚本或批处理脚本作为“胶水层”。Linux Shell脚本示例 (run_etl.sh):bash#!/bin/bash # 定义变量 export KETTLE_HOME/opt/data-integration export JOB_PATH/home/etl/jobs export LOG_PATH/home/etl/logs # 获取今天的日期作为业务日期如果没传参默认用昨天 if [ -z $1 ]; then BIZ_DATE$(date -d yesterday %Y-%m-%d) else BIZ_DATE$1 fi # 日志文件名包含日期 LOG_FILE${LOG_PATH}/daily_load_${BIZ_DATE}.log echo 开始执行作业业务日期: ${BIZ_DATE} # 执行Kitchen命令 ${KETTLE_HOME}/kitchen.sh -file${JOB_PATH}/main_control.kjb \ -param:BIZ_DATE${BIZ_DATE} \ -level:Basic \ -logfile${LOG_FILE} # 检查执行结果 if [ $? -eq 0 ]; then echo 作业执行成功 exit 0 else echo 作业执行失败请检查日志: ${LOG_FILE} exit 1 fi7.3 Windows批处理示例batchecho off rem 设置Kettle路径 set KETTLE_HOMED:\data-integration set JOB_PATHD:\etl\jobs set LOG_PATHD:\etl\logs rem 获取业务日期默认取前一天 set BIZ_DATE%1 if %BIZ_DATE% set BIZ_DATE%date:~0,4%-%date:~5,2%-%date:~8,2% set LOG_FILE%LOG_PATH%\daily_load_%BIZ_DATE%.log echo 开始执行作业业务日期: %BIZ_DATE% rem 执行Kitchen命令 %KETTLE_HOME%\kitchen.bat -file%JOB_PATH%\main_control.kjb ^ -param:BIZ_DATE%BIZ_DATE% ^ -level:Basic ^ -logfile%LOG_FILE% if %ERRORLEVEL% 0 ( echo 作业执行成功 ) else ( echo 作业执行失败请检查日志: %LOG_FILE% )这种封装方式将Kettle命令行与业务逻辑解耦调度系统只需要调用这个脚本并传入必要的业务日期即可无需关心Kettle的具体参数细节 。第八章 高级技巧循环与动态传参在数仓开发中经常需要根据某个列表进行循环处理比如遍历某个月的所有日期逐天抽取数据或者遍历所有表名对每张表执行相同的清洗逻辑。这就需要结合Kettle的循环机制和变量传递。8.1 通过“复制记录到结果”实现循环Kettle的作业提供了“复制记录到结果”Copy rows to result和“从结果获取记录”Get rows from result这一对步骤配合“作业”的“执行每一个输入行”功能可以实现循环 。8.1.1 场景按月循环处理每天的数据假设有一个月份2019需要循环处理该月每一天的数据。Step 1: 构建循环列表第一个转换创建一个转换命名为Generate_Date_List.ktr。使用“表输入”或“生成记录”步骤生成一个包含需要循环的字段的数据流。这里我们使用“表输入”从一张有日期的表中获取2019年所有不重复的日期格式化为yyyy-MM-dd字段命名为cur_month。添加“复制记录到结果”步骤。这一步的作用是将数据流复制到内存中供父作业读取。Step 2: 获取变量并执行业务逻辑第二个转换创建另一个转换命名为Process_One_Day.ktr。这个转换代表针对单天数据的处理逻辑。添加“获取变量”步骤将之前传入的字段如cur_month转换成本转换的变量如CUR_MONTH。在“表输入”等业务步骤中使用${CUR_MONTH}作为参数。Step 3: 在作业中串联循环逻辑创建一个主作业Monthly_Loop_Job.kjb。添加一个“转换”作业项选择Generate_Date_List.ktr。它的作用只是生成循环列表不执行主要逻辑。再添加一个“作业”作业项注意是“作业”不是“转换”选择Process_One_Day.ktr。关键步骤双击“作业”作业项在弹出的配置窗口中切换到“执行”选项卡勾选“执行每一个输入行”。这意味着父作业会将上一步“复制记录到结果”输出的每一行数据依次传递给这个子作业并执行一次。将两个作业项用连接线连起来第一个成功后执行第二个。当这个主作业运行时流程如下执行Generate_Date_List生成2019年的所有日期列表比如30条记录存入结果内存。进入Process_One_Day作业项由于勾选了“执行每一个输入行”该子作业会被循环执行30次。每次执行时Process_One_Day中的“获取变量”步骤都会从结果中读取一行数据将cur_month的值传给变量CUR_MONTH然后执行具体的业务逻辑。8.2 动态SQL与表名传参在循环的基础上可以实现更复杂的动态处理例如动态表名。在Process_One_Day.ktr中如果需要根据循环中的变量动态切换表名可以在“表输入”的SQL中这样写sqlSELECT * FROM ${CUR_TABLE_NAME} WHERE dt ${CUR_MONTH}或者通过“动态SQL行”步骤结合JavaScript生成完整的SQL语句后再执行。这为处理分库分表或按天/按月分区的数据提供了极大的灵活性。第九章 总结与最佳实践经过前面八章详细阐述我们对Kettle中各种传参方式有了全面的认识。本章将对其进行梳理并提供一套在实际项目中行之有效的最佳实践指南。9.1 各种传参方式对比总结方式配置/定义位置引用语法传递方式最佳应用场景全局变量kettle.properties${VAR_NAME}配置文件需重启数据库连接串、FTP地址、根路径、加密密码命名参数转换/作业属性${PARAM_NAME}属性定义命令行传入业务日期、批次号、业务主键位置参数获取系统信息步骤arg0或${arg0}按顺序传入简单的少量必填参数少于3个变量传递设置变量/获取变量步骤${VAR_NAME}字段流转变量跨步骤/转换动态计算结果传递如取最大值作为下步参数结果传递复制记录到结果步骤通过获取变量步骤在作业中跨步骤/转换传递数据集循环处理、遍历表名JavaScriptJavaScript代码步骤getVariable()函数代码内部读写复杂逻辑判断、运行时弹窗调试9.2 常见错误排查指南变量未替换这是最常见的错误。现象是SQL被原样发送给数据库如SELECT ... WHERE date ${BIZ_DATE}。解决方法检查“表输入”、“插入/更新”等所有涉及数据库操作的步骤确认“替换SQL语句里的变量”复选框已勾选 。作用域问题在转换A中用“设置变量”设置了变量在同一个转换A的后续步骤中却获取不到。原因“设置变量”的生效时机是转换结束之后。解决方法将设置和使用分离到同一个作业下的两个不同转换中 。变量名拼写错误尤其是在命令行中传入时要注意参数名的大小写虽然Kettle通常不区分但保持一致性是个好习惯。全局变量未生效修改了kettle.properties后在Spoon中运行依然看不到效果。解决方法完全重启Spoon工具 。数据类型不匹配通过“获取变量”步骤获取的变量默认是字符串类型。如果数据库字段是日期类型直接使用${VAR}可能导致类型转换错误。解决方法在“获取变量”步骤中明确指定字段的“类型”和“格式”或者在SQL中使用数据库的转换函数如TO_DATE(${VAR} YYYY-MM-DD)。9.3 推荐的设计规范命名规范统一建议所有参数和变量使用大写字母和下划线命名如LOAD_DATESRC_TABLE_NAME。这有助于在复杂的作业中快速识别出变量。分层传递顶层作业只接收外部调度系统传入的业务参数如日期。子作业明确声明自己需要哪些参数并在调用时由顶层作业映射传入不直接读取顶层作业的变量。转换同子作业通过命名参数定义接口。避免硬编码在作业或转换中不应出现任何与环境相关的硬编码字符串如IP地址、绝对路径。所有这类信息都应该抽取到kettle.properties或作为顶层参数传入。日志记录在作业开始时增加一个“写日志”步骤或一个简单的“JavaScript”步骤将本次运行的关键参数如当前执行日期${BIZ_DATE}打印到日志中。这对于事后审计和问题排查非常有帮助。合理使用作用域只有真正需要全局共享的配置才放入kettle.properties。在作业中动态生成的变量尽量使用“Valid in the parent job”或“Valid in the root job”避免污染JVM全局变量空间造成命名冲突。