☰
Kettle数据预处理作业实战:空字符串转NULL与去重清洗链路
2026/10/14 14:44:16 网站建设 项目流程

简介:这份数据预处理作业资源包面向学习ETL与数据分析的高校学生及课程设计参与者,以Kettle(Pentaho Data Integration)为核心工具,帮助完成从数据清洗、转换到加载的完整预处理实践。包内共9个文件,以6个SQL数据源脚本为主,涵盖图书馆、一卡通、学生基本信息等业务表数据,另附Word格式的实践指导手册与数据表说明文档,压缩包约136.82MB,便于直接导入Kettle进行转换与作业流程搭建。资源围绕数据清洗、缺失值处理、归一化编码、多源数据集成、采样分区及数据加载等环节展开,可对照手册逐步复现复杂预处理流程,理解Spoon、Kitchen、Pan等组件的分工与配合。目前已有1825人学习下载,适合作为课程大作业参考、ETL入门练手或数据分析前的数据准备范例,帮助读者在真实表结构上练习转换步骤配置与问题排查。

1. 数据预处理作业用 Kettle 落地:从空字符串到脏数据的完整清洗链路

很多人第一次拿到「数据预处理作业」这四个字,脑子里想的是 Python 的 pandas,写几行dropna()就交差了。但真正在企业里跑批、做 ETL 的团队,数据预处理作业往往是用 Kettle 这类可视化 ETL 工具完成的——原因很直接:作业要定时跑、要连异构数据源、要能被不懂代码的同事接手维护。Kettle 的核心价值在于把「抽取-转换-加载」拆成可复用的步骤和作业,每一步都能单独调试、单独看日志。这篇笔记就围绕一份典型的数据预处理作业展开:从 CSV 和数据库里把原始数据抽出来,做清洗、去重、类型转换、空值处理,最后落到目标表。适合正在做课程作业的学生,也适合刚接手 ETL 维护的一线工程师。下面按「先跑通最小链路,再逐个补清洗规则,最后讲坑」的顺序推进。

2. Kettle 最小可跑链路:抽一张表、洗一遍、写回去

2.1 先搞清楚转换和作业的分工

Kettle 里有两个容易混淆的概念:转换(Transformation)和作业(Job)。转换是数据流动的管道,由若干步骤(Step)和跳(Hop)组成,数据一行一行流过,做字段映射、过滤、计算。作业是控制流,负责调度——比如先检查文件是否存在,再执行转换,失败就发邮件。做数据预处理作业时,常见做法是:把清洗逻辑全部放在转换里,作业只负责「什么时候跑、跑完干什么」。

这个分工不是玄学,是有实际原因的。转换里的步骤是并行流式处理的,你没法在转换里做「如果文件不存在就跳过」这种判断;而作业的每个节点是串行执行的,适合做条件分支。我一般会建一个作业,里面挂两三个转换:一个负责抽取和清洗,一个负责加载,中间用「成功」连线串起来。这样任何一段出问题,日志能直接定位到是哪个转换挂了。

选型上,Kettle 的替代品不少,比如 DataX、Airbyte,但 Kettle 的优势是图形化配置 + 内置步骤足够多,做课程作业或中小规模批处理时,不用写一行 Java 就能覆盖 80% 的清洗场景。代价是它的内存模型比较粗暴,数据量大时要手动调提交批次,这个后面避坑章节会细说。

2.2 用 Spoon 建第一个转换:CSV 输入到表输出

Kettle 的图形客户端叫 Spoon,启动方式就是找到安装目录下的Spoon.bat(Windows)或spoon.sh(Linux)。启动后新建一个转换,从左侧「核心对象」面板拖步骤到画布。下面是一个最小链路:读 CSV,去掉空行,写到数据库表。

# 启动 Spoon(Windows 示例,路径按实际安装位置改) cd D:\kettle\data-integration Spoon.bat

拖入以下步骤并连线:

  1. 「CSV 输入」步骤:指定文件路径、分隔符、编码(中文环境务必选 UTF-8 或 GBK,选错就是乱码)。
  2. 「过滤记录」步骤:条件设为字段名 IS NOT NULL,把空行挡掉。
  3. 「表输出」步骤:配置数据库连接、目标表名,勾选「指定数据库字段」。

配置完点画布上方的运行按钮(或按 F9),Spoon 会弹出执行结果窗口,能看到读了多少行、写了多少行、耗时多少。这一步跑通,说明你的数据库驱动、连接串、表结构都是对的。

参数说明上,CSV 输入步骤里最关键的三项是:分隔符(默认逗号,但很多作业给的是制表符或分号)、编码(中文乱码九成是这里)、以及「头部行数」(如果文件第一行是列名,要设为 1 并勾选「包含列名」)。表输出步骤里,「提交记录数量」默认是 1000,意思是每攒够 1000 行往数据库提交一次,这个值直接决定内存占用和写入速度的平衡。

2.3 数据库连接与 ojdbc 驱动的放置位置

连 Oracle 时,Kettle 需要ojdbc驱动包。常见做法是把ojdbc6.jar或ojdbc8.jar放到># 确认驱动放置位置(Linux 示例) ls -l /opt/kettle/data-integration/lib/ojdbc*.jar # 重启 Spoon 让驱动生效

数据库连接配置里,连接类型选 Oracle,主机名、端口、SID/服务名按实际填。测试连接时如果报时区相关的错误,通常是 JDBC URL 里没带时区参数,可以在「选项」里加serverTimezone=Asia/Shanghai。连接成功后,表输出步骤才能正确读取目标表的字段列表。

3. 数据清洗规则逐条落地:空字符串、去重、类型转换

3.1 空字符串不转 null 的坑与「字符串替换」步骤

热词里有一条「kettle 局部修改空字符串不转换为null」,这是真实痛点。Kettle 从文本文件读进来的空字段,默认是空字符串"",不是数据库的NULL。如果你直接写进一个允许 NULL 但有空字符串约束的表,或者后续用IS NULL判断,就会漏掉这些行。

解决方式有两种。第一种是在「字段选择」步骤里,对目标字段设置「如果为空则替换为」某个值,但这样会把空字符串变成具体值,不一定是你想要的。第二种更干净:用「字符串替换」步骤,把""替换成NULL。配置时,「搜索」填^$(正则匹配空字符串),「替换为」留空并勾选「使用正则表达式」,然后在字段选择里把该字段类型设为 String,Kettle 会把空结果当作 null 处理。

-- 验证清洗结果:空字符串和 NULL 是否被正确区分 SELECT COUNT(*) AS empty_str FROM target_table WHERE col = ''; SELECT COUNT(*) AS null_val FROM target_table WHERE col IS NULL;

逻辑说明:^$匹配的是长度为 0 的字符串,替换后字段值为空,Kettle 在写入数据库时根据字段元数据决定是写''还是NULL。参数上要注意,「字符串替换」步骤默认只处理 String 类型字段,如果字段被识别成 Number,正则不会生效,需要先用「字段选择」把类型改回 String。

3.2 去重:用「排序记录」+「去除重复记录」两步走

Kettle 去重不能只靠一个步骤。正确做法是先「排序记录」按去重字段排序,再「去除重复记录」。如果跳过排序直接去重,Kettle 只会比较相邻行,结果不可靠——这是血泪经验,很多人以为去重步骤坏了,其实是没排序。

配置「排序记录」时,把要去重的字段(比如身份证号、订单号)拖进排序字段列表,升序即可。「去除重复记录」步骤里,同样把这些字段设为比较字段,并选择「只保留第一条」或「只保留最后一条」。如果数据量很大,排序会吃内存,可以在排序步骤里设置「临时文件目录」,让 Kettle 把中间结果溢写到磁盘。

# 查看排序步骤的临时文件配置(在 Spoon 中右键步骤 -> 设置) # 关键参数:排序缓存大小(默认 1000000 行),临时文件目录

参数说明:排序缓存大小决定内存里能放多少行,超过就写临时文件。做作业时数据量小,默认值够用;生产环境建议把临时目录指到空间大的盘,并监控磁盘占用。

3.3 类型转换与字段选择:日期、数字、编码的统一

原始数据里日期经常是字符串,比如20240115或2024/01/15,要转成数据库的 DATE 类型。用「字段选择」步骤的「元数据」选项卡,把字段类型从 String 改成 Date,并指定格式。数字字段同理,注意千分位逗号和小数点的问题。

编码统一是另一个高频需求。如果源文件是 GBK,目标库是 UTF-8,可以在 CSV 输入步骤直接指定编码为 GBK,Kettle 读进来后内部用 Unicode 处理,写出时按目标库编码走。不要在中途用「字符串替换」去改编码,那样容易把多字节字符截断。

-- 检查类型转换后的数据是否符合预期 SELECT TO_CHAR(create_date, 'YYYY-MM-DD') AS fmt_date, CAST(amount AS DECIMAL(10,2)) AS fmt_amount FROM target_table WHERE ROWNUM <= 10;

逻辑说明:日期格式串yyyyMMdd对应20240115,yyyy/MM/dd对应2024/01/15,格式串写错会得到 null 或报错。数字转换时,如果源字段有货币符号,要先用「字符串替换」去掉符号再转类型。

4. 作业调度与增量抽取:让预处理作业能重复跑

4.1 用作业串联转换并设置失败处理

单个转换跑通后,用作业把它们串起来。新建作业,拖入「Start」节点、「转换」节点、「成功」节点。转换节点里选择你建好的转换文件(.ktr)。如果要在转换失败时发通知,可以加「邮件」节点,连在转换的「失败」连线上。

作业的调度可以手动点运行,也可以用操作系统的定时任务。Windows 下用「任务计划程序」调用Kitchen.bat,Linux 下用 crontab 调用kitchen.sh。命令行调用的好处是能传参数,比如指定日期分区。

# Linux 下用 kitchen.sh 执行作业,传入日期参数 /opt/kettle/data-integration/kitchen.sh \ -file=/opt/jobs/preprocess_job.kjb \ -param:run_date=20240115 \ -level=Basic \ >> /var/log/kettle/preprocess_20240115.log 2>&1

参数说明:-file指定作业文件,-param:传命名参数(在转换里用${run_date}引用),-level控制日志级别(Basic 够用,Debug 会刷屏),重定向把日志落盘方便排查。

4.2 增量抽取:用「表输入」的变量替换做日期过滤

全量抽取每次跑都清空重写,数据量大时不可接受。增量抽取的常见做法是:在「表输入」步骤的 SQL 里用变量做条件过滤,比如WHERE create_date >= '${last_run_date}'。变量值由作业传入,或者从一张配置表里读上次运行时间。

-- 表输入步骤中的增量 SQL 示例 SELECT id, name, amount, create_date FROM source_table WHERE create_date >= TO_DATE('${last_run_date}', 'YYYYMMDD') AND create_date < TO_DATE('${run_date}', 'YYYYMMDD');

逻辑说明:last_run_date是上次成功运行的时间点,run_date是本次运行日期,这样每次只抽一天的数据,避免重复。参数上要注意,变量替换在 Kettle 里是文本替换,日期格式串必须和传入的字符串格式一致,否则 Oracle 会报格式错误。

4.3 用「更新/插入」步骤处理主键冲突

增量数据里可能有已存在的记录,直接「表输出」会报主键冲突。改用「插入/更新」步骤,指定主键字段,Kettle 会先查再决定插入还是更新。这个步骤比「表输出」慢,因为每行都要查一次,但能保证幂等。

配置时,「用来查询的关键字」选主键字段,「更新字段」选需要覆盖的列。如果数据量大,建议先在数据库层做 merge,或者用「表输出」写到临时表再在库里做 upsert,性能会好很多。

5. 避坑与排查:Kettle 数据预处理作业的 5 个高频翻车点

5.1 现象:中文乱码,数据库里全是问号

原因:CSV 输入步骤的编码和文件实际编码不一致,或者数据库连接的字符集不对。解决:先用文本编辑器确认文件编码,CSV 输入步骤里显式指定;数据库连接串里加characterEncoding=UTF-8;Oracle 客户端环境变量NLS_LANG设为AMERICAN_AMERICA.AL32UTF8。

5.2 现象:作业跑一半卡死,内存溢出

原因:排序、去重、表输出这些步骤默认在内存里攒数据,数据量大时撑爆 JVM 堆。解决:调大 Spoon 启动脚本里的-Xmx参数(比如-Xmx2048m),同时在排序步骤设置临时文件目录,表输出步骤把提交记录数量从 1000 降到 500 或更低。

5.3 现象:空字符串写进库变成 NULL,或者反过来

原因:Kettle 对空字符串和 NULL 的处理取决于字段类型和数据库驱动。解决:统一在「字符串替换」步骤里把空字符串转成 NULL,或者在字段选择里明确设置「如果为空则替换为」具体值。写库前用 SQL 抽样验证。

5.4 现象:ojdbc 驱动放了但连不上 Oracle

原因:驱动版本和 JDK 版本不匹配,或者驱动放错目录。解决:确认 Spoon 用的 JDK 版本(java -version),JDK 8 用 ojdbc8,JDK 11 也用 ojdbc8 但要注意模块化问题;驱动必须放>// JavaScript 代码步骤示例:手机号脱敏 + 空值兜底 var phone = phone_raw; if (phone == null || phone == '') { phone = 'UNKNOWN'; } else { phone = phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'); } // 输出到新字段 var masked_phone = phone;

逻辑说明:phone_raw是输入字段,masked_phone是输出字段,需要在步骤的「字段」列表里声明。正则(\d{3})\d{4}(\d{4})匹配 11 位手机号,中间四位替换成星号。空值兜底是为了避免脱敏后出现 null 导致后续步骤报错。

最后说个我自己的习惯:每做完一个转换,先拿 100 行样本数据跑一遍,用「文本文件输出」把结果写到本地看一眼,确认字段映射和清洗规则都对,再连生产库。这个「后悔药」动作花不了两分钟,但能省掉很多回滚的麻烦。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询