如何修复非法 Parquet 类型:INT64 (TIMESTAMP_MICROS) 错误

Posted

技术标签:

【中文标题】如何修复非法 Parquet 类型:INT64 (TIMESTAMP_MICROS) 错误【英文标题】:how to fix Illegal Parquet type: INT64 (TIMESTAMP_MICROS) error 【发布时间】:2019-08-28 20:54:38 【问题描述】:

我每天使用PySpark 中的sqlContext.read.parquet 函数来读取parquet 文件。数据有一个timestamp 列。他们将时间戳字段从2019-08-26T00:00:13.600+0000 更改为2019-08-26T00:00:13.600Z。它在 Databricks 中读取良好,但是当我尝试通过 spark 集群读取它时,它给出了 Illegal Parquet type: INT64 (TIMESTAMP_MICROS) 错误。如何使用read.parquet 函数本身阅读这个新专栏?

目前我使用:from_unixtime(unix_timestamp(ts,"yyyy-MM-dd HH:mm:ss.SSS"),"yyyy-MM-dd") 作为 ts 将2019-08-26T00:00:13.600+0000 转换为2019-08-26 格式。

如何将2019-08-26T00:00:13.600Z 转换为2019-08-26

【问题讨论】:

由于 Illegal Parquet type: INT64 (TIMESTAMP_MICROS) 错误,我无法读取 parquet 文件(通过 read.parquet(path))。 【参考方案1】:

这是scala版本

import spark.implicits._
import org.apache.spark.sql.functions._
import org.apache.spark.sql.types._

val df2 = Seq(("a3fac", "2019-08-26T00:00:13.600Z")).toDF("id", "eventTime")
val df3= df2.withColumn("eventTime1", to_date(unix_timestamp($"eventTime", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").cast(TimestampType)))

df3.show(false)
+-----+------------------------+----------+
|id   |eventTime               |eventTime1|
+-----+------------------------+----------+
|a3fac|2019-08-26T00:00:13.600Z|2019-08-26|
+-----+------------------------+----------+

下面一行是将时区日期转换为日期

to_date(unix_timestamp($"eventTime", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").cast(TimestampType))

pyspark 版本:

>>> from pyspark.sql.functions import col, to_date,unix_timestamp
>>> df2=spark.createDataFrame([("a3fac", "2019-08-26T00:00:13.600Z")], ['id', 'eventTime'])
>>> df3=df2.withColumn("eventTime1", to_date(unix_timestamp(col("eventTime"), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").cast('timestamp')))
>>> df3.show()
+-----+--------------------+----------+
|   id|           eventTime|eventTime1|
+-----+--------------------+----------+
|a3fac|2019-08-26T00:00:...|2019-08-26|
+-----+--------------------+----------+

【讨论】:

有什么隐含的方式我可以阅读/做到这一点吗?您建议的方式是明确的,我必须将我的数据转换为 df,读取路径并指定列并应用它。有什么办法可以直接读取镶木地板吗?使用 read.parquet 本身?【参考方案2】:

您可以使用功能模块中的 to_date api

import pyspark.sql.functions as f

dfl2 = spark.createDataFrame([(1, "2019-08-26T00:00:13.600Z"),]).toDF('col1', 'ts')

dfl2.show(1, False)
+----+------------------------+
|col1|ts                      |
+----+------------------------+
|1   |2019-08-26T00:00:13.600Z|
+----+------------------------+

dfl2.withColumn('date',f.to_date('ts', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")).show(1, False)

+----+------------------------+----------+
|col1|ts                      |date      |
+----+------------------------+----------+
|1   |2019-08-26T00:00:13.600Z|2019-08-26|
+----+------------------------+----------+

dfl2.withColumn('date',f.to_date('ts', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")).printSchema()
root
 |-- col1: long (nullable = true)
 |-- ts: string (nullable = true)
 |-- date: date (nullable = true)

【讨论】:

有什么隐含的方式我可以阅读/做到这一点吗?您建议的方式是明确的,我必须将我的数据转换为 df,读取路径并指定列并应用它。有什么办法可以直接读取镶木地板吗?使用 read.parquet 本身? @drv236 只读取 parquet 文件时是否出错? 是的,它向我显示 Illegal Parquet type: INT64 (TIMESTAMP_MICROS) 错误,同时尝试读取 parquet 本身。 @drv236 :好的,然后是不同的问题。当 parquet 模式从初始更改时会发生这种情况。您可以尝试使用read.option api 设置时间戳格式吗就像spark.read.option("timestampFormat", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").parquet("/path/to/parquet") 在这种情况下,所有时间戳列都应该有类似的模式 在这种情况下,需要查看 parquet 文件的文件和架构。几个选项 1. 停止推断模式:spark.read.option("inferSchema", "false")。这将以字符串格式提供您的日期,一旦您阅读,您就可以转换数据类型。 2. 如果您的 Parquet 文件像我一样位于 HDFS 或 S3 中,您可以尝试以下方法并分析文件:HDFS:parquet-tools schema hdfs://<YOUR_NAME_NODE_IP>:<PORT>/<YOUR_FILE_PATH>/<YOUR_FILE>.parquet S3:parquet-tools schema s3://<YOUR_BUCKET_PATH>/<YOUR_FILE>.parquet

以上是关于如何修复非法 Parquet 类型:INT64 (TIMESTAMP_MICROS) 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 OverflowError:int64 加法中的溢出

从 Parquet S3 复制到 Redshift 和十进制与 int 类型

BigQuery 加载镶木地板错误 - Parquet 中的字段 INT32 与架构中的 double 类型不兼容

如何修复 Flutter 中的“参数类型 'Future<int>' 无法分配给参数类型 'int'”

如何修复 hadoop 中的“非法分区”错误?

如何在此 for 循环中修复'无法将'String'类型的值转换为预期的参数类型'Int'