使用多个RowTag在Spark中读取XML文件

问题描述 投票:-1回答:3

我想在Apache Spark Dataframes中读取一个包含3个不同RowTag的巨大XML文件。

RowTag = XML元素,您将其解释为Spark中的一行。

标签

  • 包含不同的数据结构
  • 没有重叠

xml-spark(https://github.com/databricks/spark-xml)只提供一次读取一个RowTag,所以我需要读取相同的文件3次(效率不高)。

有没有办法在一次读取中读取文件?

细节:

我有一个巨大的XML文件(24 GB),其中包含3个列表:

<myFile>
    <ContainedResourceList>
        <SoundRecording><Title>A</Title></SoundRecording>
      ... several million records ...
        <SoundRecording><Title>Z</Title></SoundRecording>
    </ContainedResourceList>

    <ContainedReleaseList>
        <Release><ReleaseType>Single</ReleaseType></Release>
      ... several million records ...
        <Release><ReleaseType>LP</ReleaseType></Release>
    </ContainedReleaseList>

    <ContainedTransactionList>
        <Transaction><Sales>1</Sales></Transaction>
      ... several million records ...
        <Transaction><Sales>999</Sales></Transaction>
    </ContainedTransactionList>
</myFile>

XML文件有效。我想阅读RowTags SoundRecording,Release&Transaction。

我更喜欢Scala libs,但我很乐意任何能够读取的lib。

PS:输出和他的架构怎么样?

  • 最佳选项:一个包含3个DataFrame的数组,每个RowTag一个
  • 丑陋的选项:一个DataFrame包含所有3个数据结构的可能元素
spark-dataframe databricks apache-spark-xml
3个回答
0
投票

一种简单的方法是使用爆炸功能。您可以将rowTag设置为ContainedResourceList读取完整的xml,然后使用生成的数据框将数据框分解为新列

df.withColumn("soundRec", explode($"SoundRecording"))

您可以为要爆炸的每个标记添加多个列


0
投票

根据我对spark-xml的使用,我理解它需要XML文件中的2个标签,

  1. 根标签
  2. 行标记

你的输入文件应该如下所示,

<root>
    <row>
        <FirstField> abc </FirstField>
        <SecondField> def <SecondField>
    </row>
    <row>
        <FirstField> ghi </FirstField>
        <SecondField> jkl <SecondField>
    </row>
    .
    .
    <row>
        <FirstField> uvw </FirstField>
        <SecondField> xyz <SecondField>
    </row>
</root>

并阅读上面的文件语法是

spark-shell --packages com.databricks:spark-xml_2.11:0.5.0
import com.databricks.spark.xml._
import org.apache.spark.sql.types._
val schema = StructType(List(StructField("FirstField",StringType,true),StructField("SecondField",StringType,true)))
val df = spark.read.option("rootTag","root").option("rowTag","row").schema(schema)xml("pathToFile")

在你的情况下,你有一个rootTag作为“myFile”,但现在有行标记。因此,您可以尝试将“myFile”用作rowTag,关键点是您必须按如下方式创建架构,

val schema = StructType(List(StructField("ContainedResourceList",StringType,true),StructField("ContainedReleaseList",StringType,true),StructField("ContainedTransactionList",StringType,true)))

然后读取文件,

 val df = spark.read.option("myFile","row").schema(schema).xml("pathToFile")

现在你很好处理这个df

你有重复的SoundRecording,Release和Transaction标签,如果你为这些定义了模式,那么重复之间只有第一个值得到解析,在你的情况下是<Title>A</Title>, <ReleaseType>Single</ReleaseType>, <Sales>1</Sales>

我还没弄清楚如何在Spark-xml中解析重复的标签


0
投票

将myfile作为行标记读取将导致一个巨大的行,然后爆炸成行将由一个火花工作者完成。

您可以将它们读入3个不同的数据框,指定不同的行标签,因为每个数据框都有不同的模式。这将产生3个不同的数据帧,每个数据帧具有数百万行,这将通过spark更有效地工作。

为了加速处理,您可以预先将xml文件拆分为多个块,甚至可以将其拆分为3组文件(Splitting XML file into multiple at given tags)。这样,工作人员可以并行读取多个部件,当他们完成一个部件时,他们可以移动到下一个部件。否则,只有一个工作人员必须按顺序读取文件并使用自己的分区方式并将它们分发给工作人员。

然后你可以使用spark-s将它们连接起来,这就是你想要做的事情。

© www.soinside.com 2019 - 2024. All rights reserved.