将空数据帧保存到镶木地板会导致错误 - Spark 2.4.4

Saving empty dataframe to parquet results in error - Spark 2.4.4

我有一段代码,最后我将数据帧写入 parquet 文件。

逻辑是数据帧有时可能为空,因此出现以下错误。

df.write.format("parquet").mode("overwrite").save(somePath)

org.apache.spark.sql.AnalysisException: Parquet data source does not support null data type.;

当我打印 "df" 的架构时,我得到了下面的结果。

df.schema
res2: org.apache.spark.sql.types.StructType = 
StructType(
    StructField(rpt_date_id,IntegerType,true), 
    StructField(rpt_hour_no,ShortType,true), 
    StructField(kpi_id,IntegerType,false), 
    StructField(kpi_scnr_cd,StringType,false), 
    StructField(channel_x_id,IntegerType,false), 
    StructField(brand_id,ShortType,true), 
    StructField(kpi_value,FloatType,false), 
    StructField(src_lst_updt_dt,NullType,true), 
    StructField(etl_insrt_dt,DateType,false), 
    StructField(etl_updt_dt,DateType,false)
)

是否有一种解决方法可以只写入带有架构的空文件,或者在空文件时根本不写入文件? 谢谢

'还是空的时候根本不写文件?'检查df是否不为空然后只写它。

if (!df.isEmpty)
  df.write.format("parquet").mode("overwrite").save("somePath")

您收到的错误与您的数据框为空这一事实无关。我没有看到保存空数据框的意义,但如果你愿意,你可以这样做。如果你不相信我,试试这个:

val schema = StructType( 
    Array(
        StructField("col1",StringType,true),  
        StructField("col2",StringType,false)
    )
)

spark.createDataFrame(spark.sparkContext.emptyRDD[Row], schema)
     .write
     .format("parquet")
     .save("/tmp/test_empty_df")

您收到该错误是因为您的其中一列是 NullType 并且抛出的异常表明 "Parquet data source does not support null data type"

我不能确定为什么你有一个 Null 类型的列,但这通常发生在你从源读取数据并让 spark 推断架构时。如果该源中有一个空列,spark 将无法推断模式并将其设置为空类型。

如果是这种情况,我的建议是您在读取时指定架构

如果不是这种情况,一个可能的解决方案是将 NullType 的所有列转换为 parquet 兼容类型(如 StringType)。以下是如何操作的示例:

//df is a dataframe with a column of NullType
val df = Seq(("abc",null)).toDF("col1", "col2")
df.printSchema
root
 |-- col1: string (nullable = true)
 |-- col2: null (nullable = true)


//fold left to cast all NullType to StringType
val df1 = df.columns.foldLeft(df){
    (acc,cur) => {
        if(df.schema(cur).dataType == NullType)
            acc.withColumn(cur, col(cur).cast(StringType))
        else
            acc
    }
}
df1.printSchema
root
 |-- col1: string (nullable = true)
 |-- col2: string (nullable = true)

希望对您有所帮助