You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于HUDI表创建的Athena视图通过Spark读取时返回软删除记录的问题及解决方案咨询

基于HUDI表创建的Athena视图通过Spark读取时返回软删除记录的问题及解决方案咨询

嗨,这个问题我之前也帮同事排查过,确实是Hudi多版本和软删除特性在直接读Parquet文件时的典型表现——Athena处理Hudi视图时会自动识别并过滤软删除、旧版本记录,但Spark直接读Parquet路径相当于绕开了Hudi的元数据处理逻辑,自然会把所有历史版本的文件都读进来。下面给你几个可行的解决方案:

  • 启用Hudi自动清理机制,从根源移除旧版本和软删除记录
    Hudi自带的Cleaner组件可以自动清理过期的提交文件(包括软删除对应的记录文件)。你需要在写Hudi表时配置以下参数开启自动清理:

    • hoodie.clean.automatic=true:开启自动清理功能
    • hoodie.cleaner.policy=KEEP_LATEST_COMMITS:设置清理策略为保留最新的N次提交
    • hoodie.cleaner.commits.retained=5:指定保留的最新提交数量(可根据业务需求调整,比如3次或10次)
      配置后,每次向Hudi表写入数据时,Cleaner都会自动检查并删除超出保留次数的旧提交文件。如果需要立刻生效,也可以用Hudi CLI手动触发清理:
    hudi-cli.sh
    clean --path <你的Hudi表路径> --policy KEEP_LATEST_COMMITS --commits 3
    

    完成清理后再用Spark读Parquet路径,就只会拿到最新版本的有效数据了。

  • 在Spark中模拟视图的列标准化逻辑,直接用Hudi格式读取底层表
    既然不能直接用spark.read.format("hudi")读视图,那可以换个思路:分别读取每个底层Hudi表,在Spark里手动实现视图的列映射逻辑,这样就能利用Hudi的内置过滤自动排除软删除和旧版本记录。举个Scala示例:

    // 读取第一个Hudi表并标准化列名
    val table1DF = spark.read.format("hudi").load("path/to/hudi-table-1")
      .select(
        col("original_col_a").alias("standard_col1"),
        col("original_col_b").alias("standard_col2")
      )
    
    // 读取第二个Hudi表并标准化列名
    val table2DF = spark.read.format("hudi").load("path/to/hudi-table-2")
      .select(
        col("another_col_x").alias("standard_col1"),
        col("another_col_y").alias("standard_col2")
      )
    
    // 合并成和视图一致的统一数据集
    val unifiedResultDF = table1DF.unionByName(table2DF)
    

    这个方法不需要修改Hudi表的配置,还能保证拿到和Athena视图完全一致的结果。

  • 使用Hudi物化视图(版本兼容情况下)
    如果你的Hudi版本在0.10.0及以上,可以考虑创建Hudi物化视图。物化视图会自动同步底层表的最新状态,自动过滤软删除和旧版本数据,并且支持直接用Spark读取(不管是Hudi格式还是Parquet格式)。不过这个方案需要确认你的集群环境支持Hudi物化视图特性。

总结一下:如果想一劳永逸解决问题,优先启用Hudi的自动清理;如果暂时不能修改表配置,就用Spark模拟视图逻辑直接读Hudi表;物化视图则是长期优化的可选方案。

备注:内容来源于stack exchange,提问作者sashmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 14:52:28