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

时间:2017-08-18 09:01:36

标签: spark-dataframe databricks apache-spark-xml

我想在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&amp;事务。

我更喜欢Scala libs,但我会很高兴任何启用了读取的lib。

PS: 输出和输出怎么样?他的架构看起来像?

  • 最佳选项:包含3个DataFrame的数组,每个RowTag一个
  • 丑陋的选项:一个包含所有3个数据结构的可能元素的DataFrame

3 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分: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中的重复标签

答案 2 :(得分:0)

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

您可以将它们读取到3个不同的数据帧中,以指定不同的行标签,因为每个行都有不同的架构。这将导致3个不同的数据帧,每个数据帧具有数百万行,通过spark可以更有效地工作。

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

然后,您可以使用spark-sql将它们连接在一起,这就是您想要做的事情。