【问题标题】:Read and write empty string "" vs NULL in Spark 2.0.1在 Spark 2.0.1 中读写空字符串“” vs NULL
【发布时间】:2020-03-07 03:52:50
【问题描述】:

CSVFileFormat 似乎在字符串列中读取和写入空值作为 null。找了一圈也没找到明确的信息,所以整理了一个简单的测试。

val df = session.createDataFrame(Seq(
    (0, "a"),
    (1, "b"),
    (2, "c"),
    (3, ""),
    (4, null)
))  

df.coalesce(1).write.mode("overwrite").format("csv") 
    .option("delimiter", ",")
    .option("nullValue", "unknown")
    .option("treatEmptyValuesAsNulls", "false")
    .save(s"$path/test")

这个输出:

0,a
1,b
2,c
3,unknown
4,unknown

因此,它似乎将空字符串和null 值都视为null。读取带有空引号字符串和空值的 CSV 文件时也会发生同样的事情。目前有什么方法可以区别对待吗?

【问题讨论】:

  • 似乎他们在github.com/apache/spark/pull/14118 中明确将空字符串设置为null。并且有一个开放的 PR 可以提供空字符串与空值 - github.com/apache/spark/pull/12904
  • 你不能简单地替换null 并在写入之前和之后用不同的值清空吗?我认为您发布的其中一个链接中也提到了它。
  • @Chitral Verma 当然,这是可能的,但并不总是可行,具体取决于文件的源或目标。它还为我认为不必要的每次读取和写入添加了额外的转换步骤。
  • 无论何时合并这些更改,转换开销仍然存在。不过这只是抽象的。源和目标并不重要,因为这个问题只与 CSVFileFormat 相关

标签: csv apache-spark


【解决方案1】:

仅仅两年半之后,由于Spark 2.4.0,空字符串不再被视为等于null 值!有关功能,请参阅 this commit for a bit of detail。您的代码将在 2.4.0+ 下按预期运行:

val df = session.createDataFrame(Seq(
    (0, "a"),
    (1, "b"),
    (2, "c"),
    (3, ""),
    (4, null)
))  

df.coalesce(1).write.mode("overwrite").format("csv") 
    .option("delimiter", ",")
    .option("nullValue", "unknown")
    .option("treatEmptyValuesAsNulls", "false")
    .save(s"$path/test")

结果:

0,a
1,b
2,c
3,
4,unknown

【讨论】:

    【解决方案2】:

    我同意这种行为是一个很大的改进,但如果您使用 Sqoop 在生产环境中导出使用 Spark 创建的 CSV 文件并且您在不更改的情况下进行更新,请注意

    .option("nullValue", "null")
    

    那么您的 Sqoop 导出将失败,并且它可能会抛出一个错误,完全无法深入了解其根本原因。 100% 是 Sqoop 问题,如果可能的话,我强烈敦促每个人利用 Spark JDBC 对导出的支持,但请注意并注意。许多企业仍然严重依赖 Sqoop。

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 2011-08-02
      • 2017-03-31
      • 2013-12-01
      • 2020-12-31
      • 1970-01-01
      相关资源
      最近更新 更多