考虑以下JSON:
{"col1": "yoyo", "col2": 1.5}
{"col1": "", "col2": 6}
{"col1": "456", "col2": ""}
{"col1": 444, "col2": 12}
{"col1": null, "col2": 1.7}
{"col1": 3.14, "col2": null}
我使用(Py)Spark如下加载:
from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local[*]").getOrCreate()
df = spark.read.json("my.json")
df.show()
产生:
+----+----+
|col1|col2|
+----+----+
|yoyo| 1.5|
| | 6.0|
|null|null| <---===***
| 444|12.0|
|null| 1.7|
|3.14|null|
+----+----+
我很难理解为什么第三行无效。似乎原因是第二列中唯一的字符串是空字符串""
,这某种程度上导致了无效化。请注意,col1
在第二行中也包含一个空字符串,但该行not无效。
对我来说,这是一种非常令人困惑和意外的行为。我无法在文档中找到提示。
"456"
保留字符串col1
,为""
保留空字符串col2
。我该如何实现这种行为(对我来说,这自然得多)?使用Spark时无法在不同的列中混合使用不同的数据类型。
读取json文件时,Spark会尝试推断每列的数据类型。在这里,Spark认为col1
是字符串类型,col2
是双精度类型。可以通过读取json文件并在数据帧上使用printSchema
来确认。这意味着将根据这些推断的数据类型来解析数据。因此,Spark将尝试将""
解析为一个显然失败的double。
使用spark.read.json
时,可以设置不同的模式。在documentation中,我们有:
模式
-允许一种在解析期间处理损坏记录的模式。如果没有设置,它使用默认值PERMISSIVE
。
PERMISSIVE
:遇到损坏的记录时,将格式错误的字符串放入由columnNameOfCorruptRecord配置的字段中,并将其他字段设置为null。为了保留损坏的记录,用户可以在用户定义的模式中设置一个名为columnNameOfCorruptRecord的字符串类型字段。如果架构没有该字段,它将在解析期间删除损坏的记录。推断架构时,它会在输出架构中隐式添加columnNameOfCorruptRecord字段。DROPMALFORMED
:忽略整个损坏的记录。FAILFAST
:遇到损坏的记录时引发异常。从上面,我们可以看到默认情况下使用
PERMISSIVE
模式,并且如果遇到损坏的记录,则所有字段都将设置为null
。这就是这种情况。要确认,可以将mode
设置为FAILFAST
,
spark.read.option('mode','FAILFAST').json("my.json")
这将带来例外。