Spark读取Parquet报INT64(TIMESTAMP(NANOS,true))非法类型错误
问题根因
这个报错和PostgreSQL中存储的原始timestamp列类型无关,核心原因是导出到HDFS的Parquet文件采用了纳秒精度带时区的时间戳编码INT64 (TIMESTAMP(NANOS,true)),而当前使用的Spark版本默认不支持该精度的Parquet时间戳解析——Spark 2.x及部分3.x早期版本默认仅兼容毫秒、微秒级的INT64时间戳编码,碰到纳秒级就会直接抛类型不合法的异常。
解决方案
不需要修改PostgreSQL数据库内的列类型,根据你的实际场景选以下任意一种方案即可:
方案1:应用侧适配(优先选,改造成本最低)
不用重新导出数据,也不用动库表,只需要在读取Parquet前加对应配置开启纳秒时间戳支持即可:
# 开启纳秒时间戳解析兼容 spark.conf.set("spark.sql.parquet.outputTimestampType", "TIMESTAMP_NTZ") parqDF = spark.read.parquet("hdfs://localhost:9000/hadoop_files/sample_2022_02.parquet")
如果上述配置加完仍有兼容问题,可以在读取后手动对时间戳列做类型转换,替换成你实际的时间戳列名即可:
from pyspark.sql.functions import col # 示例:时间戳列名为event_time,按实际业务列名替换 parqDF = parqDF.withColumn("event_time", col("event_time").cast("timestamp"))
如果你的Spark版本低于2.4,内置版本完全没有纳秒时间戳解析能力,直接升级Spark到3.1及以上版本即可无改动读取文件。
方案2:导出环节调整精度(适合长期稳定运行的生产任务)
如果不方便改Spark应用的配置,可以调整从PostgreSQL导出数据到Parquet的逻辑,把时间戳的写入精度改成微秒级,从根源规避兼容问题:
- 若用Spark导出数据,写入Parquet前提前设置配置
spark.conf.set("spark.sql.parquet.outputTimestampType", "TIMESTAMP_MICROS")即可 - 若用Sqoop等其他工具导出,指定Parquet时间戳列的写入精度为微秒/毫秒即可,不需要修改原始库表的字段类型。
注意:修改PostgreSQL数据库原始列类型是投入产出比极低的方案,完全不需要做这步操作。
内容的提问来源于stack exchange,提问作者Val
相关产品推荐
相关产品推荐

