PySpark读取PyArrow写入的Pandas Parquet报INT64时间戳错误求解决
解决PySpark读取Pandas+PyArrow写入的Parquet文件时报"Illegal Parquet type: INT64 (TIMESTAMP(NANOS,false))"的问题
问题原因
Pandas通过PyArrow写入Parquet时,会将timestamp类型以纳秒精度的INT64格式存储;而Spark默认的Parquet Reader对这种类型的解析存在兼容性问题,即使是3.4.x/3.5.x版本也需要额外配置才能支持。
无需修改Parquet文件的解决方案
方案1:开启Spark对纳秒时间戳的支持(推荐,适用于Spark 3.3+)
在创建SparkSession时添加相关配置,让Spark能够识别纳秒精度的timestamp类型:
from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("ReadNanoTimestampParquet") \ .config("spark.sql.parquet.timestampNanosEnabled", "true") \ .config("spark.sql.timestampType", "TIMESTAMP_NTZ") # TIMESTAMP_NTZ表示无时区,根据实际需求选择TIMESTAMP_LTZ(带时区) .getOrCreate() # 正常读取文件 spark_df = spark.read.parquet('data/tests_dataset')
配置说明:
spark.sql.parquet.timestampNanosEnabled=true:允许Spark解析存储为INT64的纳秒精度timestampspark.sql.timestampType:指定Spark内部使用的timestamp类型,根据原数据是否带时区选择对应值
方案2:手动转换类型(适用于所有Spark版本)
如果无法升级Spark版本或配置不生效,可以先将timestamp列当作长整型读取,再手动转换为timestamp类型:
- 定义自定义Schema,将timestamp列指定为
LongType - 读取文件后,将长整型值转换为timestamp(纳秒转timestamp需除以1e9)
示例代码:
from pyspark.sql import SparkSession from pyspark.sql.types import StructType, StructField, LongType, TimestampType, StringType # 自定义Schema,替换为你的实际列结构 custom_schema = StructType([ StructField("id", StringType(), nullable=True), StructField("event_time", LongType(), nullable=True), # 其他列按实际情况添加 ]) spark = SparkSession.builder.appName("ReadParquetManualConvert").getOrCreate() # 按自定义Schema读取 raw_df = spark.read.schema(custom_schema).parquet('data/tests_dataset') # 将纳秒级长整型转换为timestamp converted_df = raw_df.withColumn("event_time", (raw_df["event_time"] / 1e9).cast(TimestampType()))
注意:如果你的Spark版本低于3.2,timestamp仅支持微秒精度,此时需将除以1e9改为除以1e6,并取整,会丢失纳秒部分的精度。
内容的提问来源于stack exchange,提问作者Stefano Castoldi
相关产品推荐
相关产品推荐

