将空数据框保存到拼花地板会导致错误-Spark 2.4.4

时间:2019-11-22 16:48:23

标签: scala apache-spark apache-spark-sql 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)
)

是否有一种变通方法是仅使用架构写入空文件,或者在为空时根本不写入文件? 谢谢

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

您得到的错误与您的数据框为空的事实无关。我看不到保存一个空数据框的意义,但是您可以根据需要进行操作。如果您不相信我,请尝试以下操作:

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将无法推断该模式,并将其设置为null类型。

如果发生这种情况,我的建议是指定读取模式

如果不是这种情况,则可能的解决方案是将NullType的所有列都转换为与拼花地板兼容的类型(如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)

希望这会有所帮助