使用spark解析/加载巨大的XML文件

时间:2018-01-16 11:42:20

标签: python xml apache-spark hive

我有一个XML文件,其中包含以下设置。

<?xml version="1.0" encoding="utf-8"?>
<SomeRoottag>
 <row Id="47513849" PostTypeId="1" />
 <row Id="4751323" PostTypeId="4" />
 <row Id="475546" PostTypeId="1" />
 <row Id="47597" PostTypeId="2" />
</SomeRoottag>

我解析文件并使用以下代码将其保存为Hive表。

df = sqlContext.read.format('xml').option("rowTag","SomeRoottag").load("/tmp/xmlfile.xml")
flat=df.withColumn("rows2",explode(df.row)).select("rows2.*")
flat.write.format("parquet").saveAsTable("xml_table")

使用我的测试数据(10mb)一切正常,但是当我加载大文件(&gt; 50G)时,它失败了。 似乎火花JVM试图加载整个文件失败,因为它只有20G大。

使用这样的文件的最佳方法是什么?

更新

如果我执行以下操作,则不会收到任何数据:

df = (sqlContext.read.format('xml').option("rowTag", "row").load("/tmp/someXML.xml"))
df.printSchema()
df.show()

输出:

root

++
||
++
++

1 个答案:

答案 0 :(得分:1)

请勿将SomeRoottag用作rowTag。它指示Spark将整个文档用作单行。代替:

df = (sqlContext.read.format('xml')
    .option("rowTag", "row")
    .load("/tmp/xmlfile.xml"))

现在没有必要爆炸:

df.write.format("parquet").saveAsTable("xml_table")

修改

考虑到您的编辑,您会受到已知错误的影响。请参阅Self-closing tags are not supported as top-level rows #92。看起来目前在解决这个方面没有任何进展,所以你可能不得不:

  • 自己制作公关来解决这个问题。
  • 手动解析文件。如果元素始终是单行,则可以使用udf轻松完成。

    from pyspark.sql.functions import col, udf
    from lxml import etree
    
    @udf("struct<id: string, postTypeId: string>")
    def parse(s):
        try:
            attrib = etree.fromstring(s).attrib
            return attrib.get("Id"), attrib.get("PostTypeId")
        except:
            pass
    
    (spark.read.text("/tmp/someXML.xml")
        .where(col("value").rlike("^\\s*<row "))
        .select(parse("value").alias("value"))
        .select("value.*")
        .show())
    
    # +--------+----------+
    # |      id|postTypeId|
    # +--------+----------+
    # |47513849|         1|
    # | 4751323|         4|
    # |  475546|         1|
    # |   47597|         2|
    # +--------+----------+