Spark的int96时间类型

时间:2017-03-06 14:35:23

标签: datetime apache-spark parquet

当你在spark中创建一个时间戳列并保存到镶木地板时,你得到一个12字节的整数列类型(int96);我收集的数据分为6个字节的Julian日和6个字节的纳秒,在一天内。

这不符合任何镶木地板logical type。然后,镶木地板文件中的模式不会指示列不是整数。

我的问题是,Spark如何知道将这样的列加载为时间戳而不是大整数?

1 个答案:

答案 0 :(得分:4)

语义是基于元数据确定的。我们需要一些进口:

import org.apache.parquet.hadoop.ParquetFileReader
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.hadoop.conf.Configuration

示例数据:

val path = "/tmp/ts"

Seq((1, "2017-03-06 10:00:00")).toDF("id", "ts")
  .withColumn("ts", $"ts".cast("timestamp"))
  .write.mode("overwrite").parquet(path)

和Hadoop配置:

val conf = spark.sparkContext.hadoopConfiguration
val fs = FileSystem.get(conf)

现在我们可以访问Spark元数据:

ParquetFileReader
  .readAllFootersInParallel(conf, fs.getFileStatus(new Path(path)))
  .get(0)
  .getParquetMetadata
  .getFileMetaData
  .getKeyValueMetaData
  .get("org.apache.spark.sql.parquet.row.metadata")

结果是:

String = {"type":"struct","fields: [
  {"name":"id","type":"integer","nullable":false,"metadata":{}},
  {"name":"ts","type":"timestamp","nullable":true,"metadata":{}}]}

等效信息也可以存储在Metastore中。

根据官方文档,这用于实现与Hive和Impala的兼容性:

  

一些Parquet生产系统,特别是Impala和Hive,将时间戳存储到INT96中。此标志告诉Spark SQL将INT96数据解释为时间戳,以提供与这些系统的兼容性。

可以使用spark.sql.parquet.int96AsTimestamp属性进行控制。