首页 > 解决方案 > 使用 spark.xml 读取 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 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”中的结构/数组——但这当然需要先填充)

有谁知道为什么这会导致解析时模式停止加载完成?

请注意,我无法明确定义架构。这将违背我正在从事的项目的目的——我必须能够动态地推断模式。这同样适用于我正在使用的其他文件。

标签: pythonxmlapache-sparkpysparkdatabricks

解决方案


原因:

所以我能够弄清楚为什么会这样。当您尝试转换为数据框的 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>

在这里,由于每个条目中都有 value="" rowTag,因此我们可能会在数据框中为所有行获取 null,因为它无法推断数据类型。但是,如果您将所有value=""字段替换为某个实际值,您将看到不会发生此问题。

解决方案:

根据databricks 链接option("nullValue", ""),可以通过在读取 xml 文件时使用选项来解决此问题。所以你的命令看起来像这样(我在 scala 中尝试过,在 python 中应该类似):

var xmldf = sparkSession.read.format("com.databricks.spark.xml")
        .option("rowTag", rootTag).option("nullValue", "").load("/path/to/xml")

推荐阅读