Spark将csv列中的空值视为null数据类型

时间:2017-09-27 04:16:11

标签: apache-spark-sql spark-dataframe

我的spark应用程序读取csv文件,使用sql将其转换为其他格式,并将结果数据帧写入不同的csv文件。

例如,我输入csv如下:

Id|FirstName|LastName|LocationId
1|John|Doe|123
2|Alex|Doe|234

我的转变是:

Select Id, 
       FirstName, 
       LastName, 
       LocationId as PrimaryLocationId,
       null as SecondaryLocationId
from Input

(我无法回答为什么将null用作SecondaryLocationId,这是业务用例) 现在,spark无法找出SecondaryLocationId的数据类型并在架构中返回null,并在写入输出csv时抛出错误 CSV数据源不支持空数据类型

以下是我正在使用的printSchema()和写入选项。

root
     |-- Id: string (nullable = true)
     |-- FirstName: string (nullable = true)
     |-- LastName: string (nullable = true)
     |-- PrimaryLocationId: string (nullable = false)
     |-- SecondaryLocationId: null (nullable = true)

dataFrame.repartition(1).write
      .mode(SaveMode.Overwrite)
      .option("header", "true")
      .option("delimiter", "|")
      .option("nullValue", "")
      .option("inferSchema", "true")
      .csv(outputPath)

有没有办法默认为数据类型(如字符串)? 顺便说一句,我可以通过用空字符串替换 null 来实现这一点('')但这不是我想要做的。

1 个答案:

答案 0 :(得分:3)

使用lit(null):import org.apache.spark.sql.functions。{lit,udf}

示例:

import org.apache.spark.sql.functions.{lit, udf}

case class Record(foo: Int, bar: String)
val df = Seq(Record(1, "foo"), Record(2, "bar")).toDF

val dfWithFoobar = df.withColumn("foobar", lit(null: String))


scala> dfWithFoobar.printSchema
root
|-- foo: integer (nullable = false)
|-- bar: string (nullable = true)
|-- foobar: null (nullable = true)
and it is not retained by the csv writer. If it is a hard requirement you 
 can cast column to the specific type (lets say String):

import org.apache.spark.sql.types.StringType
df.withColumn("foobar", lit(null).cast(StringType))

或使用这样的UDF:

val getNull = udf(() => None: Option[String]) // Or some other type

df.withColumn("foobar", getNull()).printSchema

root
 |-- foo: integer (nullable = false)
 |-- bar: string (nullable = true)
 |-- foobar: string (nullable = true)

重新发布zero323代码。

现在让我们讨论你的第二个问题

问题:

"只有当我知道哪些列将被视为空数据类型时。当正在读取大量文件并应用各种转换时,我不知道或者有什么方法可以知道哪些字段被空处理? "

答案

在这种情况下,您可以使用选项

Databricks Scala style guide不同意应始终禁止在Scala代码中使用null,并说:“对于性能敏感的代码,首选null而不是Option,以避免虚拟方法调用和装箱。”

示例:

+------+
|number|
+------+
|     1|
|     8|
|    12|
|  null|
+------+


val actualDf = sourceDf.withColumn(
  "is_even",
  when(
    col("number").isNotNull, 
    isEvenSimpleUdf(col("number"))
  ).otherwise(lit(null))
)

actualDf.show()
+------+-------+
|number|is_even|
+------+-------+
|     1|  false|
|     8|   true|
|    12|   true|
|  null|   null|
+------+-------+