Parquet文件在读到Spark 3.3.0时没有保持schema的非空性



我从CSV文件中读取数据,并提供一个手工编写的模式:

new StructType(new StructField[] {
new StructField("id", LongType, false, Metadata.empty(),
new StructField("foo", IntegerType, false, Metadata.empty(),
new StructField("bar", DateType, true, Metadata.empty()) });

打印模式显示:

root
|-- id: long (nullable = false)
|-- foo: integer (nullable = false)
|-- bar: date (nullable = true)

并使用以下代码将其写入parquet文件…

df.write().format("parquet").save("data.parquet");

…生成此日志消息:

INFO : o.a.s.s.e.d.p.ParquetWriteSupport: Initialized Parquet WriteSupport with Catalyst schema:
{
"type" : "struct",
"fields" : [ {
"name" : "id",
"type" : "long",
"nullable" : false,
"metadata" : { }
}, {
"name" : "foo",
"type" : "integer",
"nullable" : false,
"metadata" : { }
}, {
"name" : "bar",
"type" : "date",
"nullable" : true,
"metadata" : { }
} ]
}
and corresponding Parquet message type:
message spark_schema {
required int64 id;
required int32 foo;
optional int32 bar (DATE);
}

一切都很好。

但是,如果我用下面的代码读取那个parquet文件:
Dataset<Row> read = spark.read().format("parquet").load("data.parquet");

…并打印模式,得到:

root
|-- id: long (nullable = true)
|-- foo: integer (nullable = true)
|-- bar: date (nullable = true)

从上面可以看到,所有的列都变成了可空的——原始模式中指定的非空性已经丢失了。

现在,如果我们看一下加载期间输出的一些调试,它显示Spark正确地识别了空性。(我添加了换行符以使其更具可读性):

FileMetaData(
version:1, 
schema:[SchemaElement(name:spark_schema, num_children:4), 
SchemaElement(type:INT64, repetition_type:REQUIRED, name:id), 
SchemaElement(type:INT32, repetition_type:REQUIRED, name:foo), 
SchemaElement(type:INT32, repetition_type:OPTIONAL, name:bar, converted_type:DATE, logicalType:<LogicalType DATE:DateType()>)], 
num_rows:7, 
row_groups:null, 
key_value_metadata:
[
KeyValue(key:org.apache.spark.version, value:3.3.0), 
KeyValue(
key:org.apache.spark.sql.parquet.row.metadata, 
value:{
"type":"struct",
"fields":
[
{"name":"id","type":"long","nullable":false,"metadata":{}},
{"name":"foo","type":"integer","nullable":false,"metadata":{}},
{"name":"bar","type":"date","nullable":true,"metadata":{}}
]
})
], 
created_by:parquet-mr version 1.12.2 (build 77e30c8093386ec52c3cfa6c34b7ef3321322c94))

那么问题是:为什么(以及在哪里)非空性丢失了?我怎么能确保这nullability铺文件中的信息是正确保存当阅读吗?(注意,在我的实际用例中,我不能再次手工应用模式,我需要它在parquet文件中携带,并在读取时正确地重构)。

这是一个有文档记录的行为。从https://spark.apache.org/docs/3.3.0/sql-data-sources-parquet.html

Parquet是许多其他数据处理系统支持的列格式。Spark SQL提供了对Parquet文件的读写支持,这些文件自动保留了原始数据的模式。当读取Parquet文件时,出于兼容性原因,所有列都会自动转换为可空。

最新更新