Spark:如何从具有属性的多个嵌套 XML 文件转换为 Data Frame 数据

Posted

技术标签:

【中文标题】Spark:如何从具有属性的多个嵌套 XML 文件转换为 Data Frame 数据【英文标题】:Spark: How to transform to Data Frame data from multiple nested XML files with attributes 【发布时间】:2020-12-31 23:59:30 【问题描述】:

如何将以下值从多个 XML 文件转换为 spark 数据框:

属性Id0来自Level_0 Date/Value 来自Level_4

需要的输出:

+----------------+-------------+---------+
|Id0             |Date         |Value    |
+----------------+-------------+---------+
|Id0_value_file_1|  2021-01-01 |   4_1   |
|Id0_value_file_1|  2021-01-02 |   4_2   |
|Id0_value_file_2|  2021-01-01 |   4_1   |
|Id0_value_file_2|  2021-01-02 |   4_2   |
+----------------+-------+---------------+

file_1.xml:

<Level_0 Id0="Id0_value_file1">
  <Level_1 Id1_1 ="Id3_value" Id_2="Id2_value">
    <Level_2_A>A</Level_2_A>
    <Level_2>
      <Level_3>
        <Level_4>
          <Date>2021-01-01</Date>
          <Value>4_1</Value>
        </Level_4>
        <Level_4>
          <Date>2021-01-02</Date>
          <Value>4_2</Value>
        </Level_4>
      </Level_3>
    </Level_2>
  </Level_1>
</Level_0>

file_2.xml:

<Level_0 Id0="Id0_value_file2">
  <Level_1 Id1_1 ="Id3_value" Id_2="Id2_value">
    <Level_2_A>A</Level_2_A>
    <Level_2>
      <Level_3>
        <Level_4>
          <Date>2021-01-01</Date>
          <Value>4_1</Value>
        </Level_4>
        <Level_4>
          <Date>2021-01-02</Date>
          <Value>4_2</Value>
        </Level_4>
      </Level_3>
    </Level_2>
  </Level_1>
</Level_0>

当前代码示例:

files_list = ["file_1.xml", "file_2.xml"]
df = (spark.read.format('xml')
           .options(rowTag="Level_4")
           .load(','.join(files_list))

当前输出:(Id0 缺少属性的列)

+-------------+---------+
|Date         |Value    |
+-------------+---------+
|  2021-01-01 |     4_1 |
|  2021-01-02 |     4_2 |
|  2021-01-01 |     4_1 |
|  2021-01-02 |     4_2 |
+-------+---------------+

有一些例子,但没有一个能解决问题: -我正在使用数据块 spark_xml -https://github.com/databricks/spark-xml - 有一个例子,但没有属性读取,Read XML in spark,Extracting tag attributes from xml using sparkxml。

编辑: 正如@mck 正确指出的那样,&lt;Level_2&gt;A&lt;/Level_2&gt; 不是正确的 XML 格式。我的示例中有一个错误(现在更正了 xml 文件),它应该是 &lt;Level_2_A&gt;A&lt;/Level_2_A&gt;。之后,建议的解决方案甚至适用于多个文件。

注意:为了加快加载大量 xml 定义架构,如果没有定义架构,则在创建数据框以干扰架构时,火花正在读取每个文件... 欲了解更多信息:https://szczeles.github.io/Reading-JSON-CSV-and-XML-files-efficiently-in-Apache-Spark/

第 1 步):

 files_list = ["file_1.xml", "file_2.xml"]
 # for schema seem NOTE above

 df = (spark.read.format('xml')
               .options(rowTag="Level_0")
               .load(','.join(files_list),schema=schema))
df.printSchema()

root
 |-- Level_1: struct (nullable = true)
 |    |-- Level_2: struct (nullable = true)
 |    |    |-- Level_3: struct (nullable = true)
 |    |    |    |-- Level_4: array (nullable = true)
 |    |    |    |    |-- element: struct (containsNull = true)
 |    |    |    |    |    |-- Date: string (nullable = true)
 |    |    |    |    |    |-- Value: string (nullable = true)
 |    |-- Level_2_A: string (nullable = true)
 |    |-- _Id1_1: string (nullable = true)
 |    |-- _Id_2: string (nullable = true)
 |-- _Id0: string (nullable = true

第 2 步)见下文@mck 解决方案:

【问题讨论】:

【参考方案1】:

您可以使用Level_0 作为rowTag,并分解相关的数组/结构:

import pyspark.sql.functions as F

df = spark.read.format('xml').options(rowTag="Level_0").load('line_removed.xml')

df2 = df.select(
    '_Id0', 
    F.explode_outer('Level_1.Level_2.Level_3.Level_4').alias('Level_4')
).select(
    '_Id0',
    'Level_4.*'
)

df2.show()
+---------------+----------+-----+
|           _Id0|      Date|Value|
+---------------+----------+-----+
|Id0_value_file1|2021-01-01|  4_1|
|Id0_value_file1|2021-01-02|  4_2|
+---------------+----------+-----+

【讨论】:

你是明星!关于 XML 行应该是&lt;Level_2_A&gt;A&lt;/Level_2_A&gt; @Dan nice,这样就解决了这个问题

以上是关于Spark:如何从具有属性的多个嵌套 XML 文件转换为 Data Frame 数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 databricks 在 Spark(scala) 中生成具有属性和值的 XML

spark-xml 中具有嵌套父节点的自定义模式

Spark - 如何从 S3 读取具有文件名的多个 Json 文件

如何从 Spark-Structured-Streaming 中的嵌套 XML_String 中提取信息

如何在具有 xmlns 属性的 xml 中使用 xpath 获取特定的嵌套元素? [复制]

linq 问题:查询嵌套集合