Apache Hudi:如何理解upsert写操作搭配Spark SaveMode.Append的逻辑?
Apache Hudi中Upsert搭配SaveMode.Append的场景解析
核心逻辑:Hudi写操作和Spark SaveMode的适配关系
Hudi的upsert是它自身的核心写逻辑——依靠主键判断是更新已有记录还是插入新数据;而Spark的SaveMode是Spark层面的写入规则,但Hudi对这套规则做了适配,不会完全照搬原生Spark的行为:
- 只要指定了Hudi的写操作是
upsert,不管设置的是Append还是Overwrite,Hudi都会执行主键匹配的更新/插入逻辑,这是Hudi作为数据湖的特性决定的。
为什么选Append而非Overwrite?
(1)避免无意义的全量重写
原生Spark的Overwrite会直接清空目标表再写入,但Hudi的Overwrite模式虽然不会真删数据,但会触发全量重写整个表的所有数据文件,大表场景下这会带来极高的IO和资源消耗。而Append模式下,Hudi只会处理本次写入涉及的分区或数据文件,只重写有变更的部分,性能优势明显。
(2)保留历史版本(版本表场景)
如果用的是Hudi的COPY_ON_WRITE或MERGE_ON_READ表类型,Append模式不会破坏已有的数据版本,能正常支持时间旅行、增量查询这类Hudi的核心特性;而Overwrite会直接重置表的版本信息,之前的历史数据会丢失。
(3)贴合增量写入的设计初衷
Hudi本身就是为增量数据湖设计的,Append模式更符合它的定位——每次upsert都是在已有数据基础上做增量的更新/插入,而不是把整个表全量替换掉。
Append和Overwrite在Hudi里的具体区别
| 对比维度 | SaveMode.Append | SaveMode.Overwrite |
|---|---|---|
| 数据处理范围 | 仅处理本次写入中匹配主键的记录,只重写涉及的文件 | 全量重写整个表的所有数据文件 |
| 历史数据保留 | 保留所有历史版本(版本表) | 重置表版本,丢失历史数据 |
| 性能开销 | 低,仅处理增量变更 | 高,全量重写文件 |
| 适用场景 | 日常增量更新/插入、实时数据同步 | 表结构变更后全量重写、初始化全量写入 |
示例说明
你提供的示例代码中,SaveMode.Append搭配Hudi的upsert,本质是告诉Hudi:在已有表的基础上,根据主键做更新或插入,只处理本次的增量数据,不要全量覆盖整个表。这种配置是Hudi日常增量更新的标准写法,既能实现upsert的核心功能,又能保证写入性能和历史数据的完整性。
内容的提问来源于stack exchange,提问作者Spencer
相关产品推荐
相关产品推荐

