为什么在使用 spark.xml 读取 XML 时我的数据框加载了空白值? (Python/Databricks)
Why is my data frame loaded with blank values when reading XML using spark.xml? (Python/Databricks)
我正在使用 Python 和 运行 中的 spark.xml 阅读一个 XML 文件,解决一个看似非常具体的问题。
我能够缩小产生问题的 XML 的部分,但不是它发生的原因。
这是要在 XML 文件中读取的代码:
src = sqlContext.read.format("com.databricks.spark.xml").options(rowTag="root").load("file.xml")
这是使用 spark.xml 库从 XML 读入的模式,rowTag = "root":
root
|-- AID: long (nullable = true)
|-- RID: long (nullable = true)
|-- XmlData: struct (nullable = true)
| |-- NC: struct (nullable = true)
| | |-- RS: struct (nullable = true)
| | | |-- RD: struct (nullable = true)
| | | | |-- CR: struct (nullable = true)
| | | | | |-- Addr1: string (nullable = true)
| | | | | |-- Addr2: string (nullable = true)
| | | | | |-- City: string (nullable = true)
| | | | | |-- InFile: string (nullable = true)
| | | | | |-- Name: string (nullable = true)
| | | | | |-- Phone: long (nullable = true)
| | | | | |-- State: string (nullable = true)
| | | | | |-- Zip: long (nullable = true)
| | | | |-- SC: struct (nullable = true)
| | | | | |-- Class: string (nullable = true)
| | | | | |-- ClassType: string (nullable = true)
| | | | | |-- Message: string (nullable = true)
| | | | | |-- SC: long (nullable = true)
| | | | |-- NC: long (nullable = true)
| | | | |-- CRR: string (nullable = true)
| | | | |-- RM: struct (nullable = true)
| | | | | |-- Addr1: string (nullable = true)
| | | | | |-- City: string (nullable = true)
| | | | | |-- MemberNo: string (nullable = true)
| | | | | |-- Name: string (nullable = true)
| | | | | |-- State: string (nullable = true)
| | | | | |-- Zip: long (nullable = true)
| | | | |-- TL: array (nullable = true)
| | | | | |-- element: struct (containsNull = true)
| | | | | | |-- _AvgDays: long (nullable = true)
| | | | | | |-- _Comment: string (nullable = true)
| | | | | | |-- _Current: long (nullable = true)
| | | | | | |-- _HC: long (nullable = true)
| | | | | | |-- _IndType: string (nullable = true)
| | | | | | |-- _LS: long (nullable = true)
| | | | | | |-- _OpenDate: long (nullable = true)
| | | | | | |-- _PD120Day: long (nullable = true)
| | | | | | |-- _PD30Day: long (nullable = true)
| | | | | | |-- _PD60Day: long (nullable = true)
| | | | | | |-- _PD90Day: long (nullable = true)
| | | | | | |-- _Region: string (nullable = true)
| | | | | | |-- _ReportDate: string (nullable = true)
| | | | | | |-- _SourceID: long (nullable = true)
| | | | | | |-- _TD: long (nullable = true)
| | | | | | |-- _VALUE: string (nullable = true)
| | | | |-- Trends: array (nullable = true)
| | | | | |-- element: struct (containsNull = true)
| | | | | | |-- _CurrentPct: double (nullable = true)
| | | | | | |-- _LineCnt: long (nullable = true)
| | | | | | |-- _PD120DayPct: double (nullable = true)
| | | | | | |-- _PD30DayPct: double (nullable = true)
| | | | | | |-- _PD60DayPct: double (nullable = true)
| | | | | | |-- _PD90DayPct: double (nullable = true)
| | | | | | |-- _PD: string (nullable = true)
| | | | | | |-- _TD: long (nullable = true)
| | | | | | |-- _VALUE: string (nullable = true)
此模式还有更多内容,但由于某种原因,XML 解析器无法通过这一点。
我认为 XML 中的“Trends”标签有问题,但我找不到它。
这是一个 'Trends' 标签条目的示例:
<Trends PD="4205" LineCnt="0" TD="0" CurrentPct="0" PD30DayPct="0" PD60DayPct="0" PD90DayPct="0" PD120DayPct="0" />
我知道像这样的闭合标签无法在以前版本的 XML 解析器中读取,但在 Databricks 中使用它时它工作正常,并且我的其他带有闭合标签的文件被读取正确。
这是进一步举例说明我所解释内容的最终结果(我的 XML 中有 13 条记录):
+---------+--------+-------+
|AID |RID |XmlData|
+---------+--------+-------+
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
+---------+--------+-------+
(这个顶级视图很好 - 我的代码稍后遍历 'XMLData' 中的 structs/arrays - 但当然需要首先填充它)
有谁知道为什么这会导致架构在解析时停止加载完成?
请注意,我无法明确定义架构。这将违背我正在从事的项目的目的——我必须能够动态地推断模式。这同样适用于我正在使用的其他文件。
原因:
所以我能够弄清楚为什么会这样。当您尝试转换为数据框的 xml 具有不一致的值时,您可能会看到此问题。例如,像下面这样的东西会出现这个问题:
<?xml version="1.0"?>
<Company>
<Employee id="1">
<Email>tp@xyz.com</Email>
<Measures id="id32" type="AttributesInContext">
<Dimensions value="7in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
<Employee id="2">
<Email>tp@xyz.com</Email>
<Measures id="id33" type="AttributesInContext">
<Dimensions value="6in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
<Employee id="3">
<Email>tp@xyz.com</Email>
<Measures id="id34" type="AttributesInContext">
<Dimensions value="4in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
</Company>
这里,由于每个 rowTag
条目中都有 value="",我们很可能会在所有行的数据框中得到 null,因为它无法推断数据类型。但是,如果您将所有 value=""
字段替换为一些实际值,您会发现此问题不会发生。
解法:
根据 databricks link,可以通过在读取 xml 文件时使用 option("nullValue", "")
选项来解决此问题。所以你的命令看起来像这样(我在 scala 中试过这个,在 python 中应该是类似的):
var xmldf = sparkSession.read.format("com.databricks.spark.xml")
.option("rowTag", rootTag).option("nullValue", "").load("/path/to/xml")
我正在使用 Python 和 运行 中的 spark.xml 阅读一个 XML 文件,解决一个看似非常具体的问题。
我能够缩小产生问题的 XML 的部分,但不是它发生的原因。
这是要在 XML 文件中读取的代码:
src = sqlContext.read.format("com.databricks.spark.xml").options(rowTag="root").load("file.xml")
这是使用 spark.xml 库从 XML 读入的模式,rowTag = "root":
root
|-- AID: long (nullable = true)
|-- RID: long (nullable = true)
|-- XmlData: struct (nullable = true)
| |-- NC: struct (nullable = true)
| | |-- RS: struct (nullable = true)
| | | |-- RD: struct (nullable = true)
| | | | |-- CR: struct (nullable = true)
| | | | | |-- Addr1: string (nullable = true)
| | | | | |-- Addr2: string (nullable = true)
| | | | | |-- City: string (nullable = true)
| | | | | |-- InFile: string (nullable = true)
| | | | | |-- Name: string (nullable = true)
| | | | | |-- Phone: long (nullable = true)
| | | | | |-- State: string (nullable = true)
| | | | | |-- Zip: long (nullable = true)
| | | | |-- SC: struct (nullable = true)
| | | | | |-- Class: string (nullable = true)
| | | | | |-- ClassType: string (nullable = true)
| | | | | |-- Message: string (nullable = true)
| | | | | |-- SC: long (nullable = true)
| | | | |-- NC: long (nullable = true)
| | | | |-- CRR: string (nullable = true)
| | | | |-- RM: struct (nullable = true)
| | | | | |-- Addr1: string (nullable = true)
| | | | | |-- City: string (nullable = true)
| | | | | |-- MemberNo: string (nullable = true)
| | | | | |-- Name: string (nullable = true)
| | | | | |-- State: string (nullable = true)
| | | | | |-- Zip: long (nullable = true)
| | | | |-- TL: array (nullable = true)
| | | | | |-- element: struct (containsNull = true)
| | | | | | |-- _AvgDays: long (nullable = true)
| | | | | | |-- _Comment: string (nullable = true)
| | | | | | |-- _Current: long (nullable = true)
| | | | | | |-- _HC: long (nullable = true)
| | | | | | |-- _IndType: string (nullable = true)
| | | | | | |-- _LS: long (nullable = true)
| | | | | | |-- _OpenDate: long (nullable = true)
| | | | | | |-- _PD120Day: long (nullable = true)
| | | | | | |-- _PD30Day: long (nullable = true)
| | | | | | |-- _PD60Day: long (nullable = true)
| | | | | | |-- _PD90Day: long (nullable = true)
| | | | | | |-- _Region: string (nullable = true)
| | | | | | |-- _ReportDate: string (nullable = true)
| | | | | | |-- _SourceID: long (nullable = true)
| | | | | | |-- _TD: long (nullable = true)
| | | | | | |-- _VALUE: string (nullable = true)
| | | | |-- Trends: array (nullable = true)
| | | | | |-- element: struct (containsNull = true)
| | | | | | |-- _CurrentPct: double (nullable = true)
| | | | | | |-- _LineCnt: long (nullable = true)
| | | | | | |-- _PD120DayPct: double (nullable = true)
| | | | | | |-- _PD30DayPct: double (nullable = true)
| | | | | | |-- _PD60DayPct: double (nullable = true)
| | | | | | |-- _PD90DayPct: double (nullable = true)
| | | | | | |-- _PD: string (nullable = true)
| | | | | | |-- _TD: long (nullable = true)
| | | | | | |-- _VALUE: string (nullable = true)
此模式还有更多内容,但由于某种原因,XML 解析器无法通过这一点。 我认为 XML 中的“Trends”标签有问题,但我找不到它。
这是一个 'Trends' 标签条目的示例:
<Trends PD="4205" LineCnt="0" TD="0" CurrentPct="0" PD30DayPct="0" PD60DayPct="0" PD90DayPct="0" PD120DayPct="0" />
我知道像这样的闭合标签无法在以前版本的 XML 解析器中读取,但在 Databricks 中使用它时它工作正常,并且我的其他带有闭合标签的文件被读取正确。
这是进一步举例说明我所解释内容的最终结果(我的 XML 中有 13 条记录):
+---------+--------+-------+
|AID |RID |XmlData|
+---------+--------+-------+
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
| null| null| null|
+---------+--------+-------+
(这个顶级视图很好 - 我的代码稍后遍历 'XMLData' 中的 structs/arrays - 但当然需要首先填充它)
有谁知道为什么这会导致架构在解析时停止加载完成?
请注意,我无法明确定义架构。这将违背我正在从事的项目的目的——我必须能够动态地推断模式。这同样适用于我正在使用的其他文件。
原因:
所以我能够弄清楚为什么会这样。当您尝试转换为数据框的 xml 具有不一致的值时,您可能会看到此问题。例如,像下面这样的东西会出现这个问题:
<?xml version="1.0"?>
<Company>
<Employee id="1">
<Email>tp@xyz.com</Email>
<Measures id="id32" type="AttributesInContext">
<Dimensions value="7in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
<Employee id="2">
<Email>tp@xyz.com</Email>
<Measures id="id33" type="AttributesInContext">
<Dimensions value="6in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
<Employee id="3">
<Email>tp@xyz.com</Email>
<Measures id="id34" type="AttributesInContext">
<Dimensions value="4in" title="Height"></Dimensions>
<Dimensions value="" title="Weight"></Dimensions></Measures>
</Employee>
</Company>
这里,由于每个 rowTag
条目中都有 value="",我们很可能会在所有行的数据框中得到 null,因为它无法推断数据类型。但是,如果您将所有 value=""
字段替换为一些实际值,您会发现此问题不会发生。
解法:
根据 databricks link,可以通过在读取 xml 文件时使用 option("nullValue", "")
选项来解决此问题。所以你的命令看起来像这样(我在 scala 中试过这个,在 python 中应该是类似的):
var xmldf = sparkSession.read.format("com.databricks.spark.xml")
.option("rowTag", rootTag).option("nullValue", "").load("/path/to/xml")