Python 针对25GB数据的高效XML解析

Python 针对25GB数据的高效XML解析,python,xml,xml-parsing,beautifulsoup,lxml,Python,Xml,Xml Parsing,Beautifulsoup,Lxml,我的目标是解析25GB的XML数据。下面给出了此类数据的示例: <Document> <Data Id='12' category='1' Body="abc"/> <Data Id='13' category='1' Body="zwq"/> . . <Data Id='82018030' category='2' CorrespondingCategory1Id='13' Body="pqr"/> . . 然而,考虑到我拥有的“25G

我的目标是解析25GB的XML数据。下面给出了此类数据的示例:

<Document>
<Data Id='12' category='1'  Body="abc"/>
<Data Id='13' category='1'  Body="zwq"/>
.
.
<Data Id='82018030' category='2' CorrespondingCategory1Id='13' Body="pqr"/>

.
.

然而,考虑到我拥有的“25GB”数据,我的方法效率很低。请建议一些改进我的代码的方法或替代方法。另外,请提供一个小示例代码,以使事情更清楚。

我对您的问题的第一个建议是使用关系数据库,如MySQL或sqlite。将XML数据转换成这种形式并不困难,然后对该数据进行查询将更加直接和快速。

我对您的问题的第一个建议是使用关系数据库,如MySQL或sqlite。将XML数据转换成这种形式并不困难,然后对该数据进行查询将更加直接和快速。

您可能会发现SAX解析器更适合此任务。SAX解析器不是构建DOM,而是将XML文件转换为元素流,并调用您提供的函数来处理每个元素

好的方面是,与DOM解析器相比,SAX解析器速度非常快,内存效率也非常高,有些解析器甚至不需要一次提供所有XML,如果您有25GB的XML,这将非常理想

不幸的是,如果您需要任何上下文信息,比如“我想要标记
,但只有当它在标记
”中时,您必须自己维护它,因为解析器给您的只是“开始标记
,开始标记
,结束标记
,结束标记
”它从不明确地告诉您标签
在标签
内,您必须从您看到的内容中找出这一点。一旦你看到了一个元素,它就消失了,除非你自己记得它

对于复杂的解析工作来说,这会变得非常棘手,但您的任务可能是可以管理的


Python的标准库碰巧在
xml.SAX
中有一个SAX解析器。您可能需要类似于
xml.sax.xmlreader.IncrementalParser

的东西,您可能会发现sax解析器更适合此任务。SAX解析器不是构建DOM,而是将XML文件转换为元素流,并调用您提供的函数来处理每个元素

好的方面是,与DOM解析器相比,SAX解析器速度非常快,内存效率也非常高,有些解析器甚至不需要一次提供所有XML,如果您有25GB的XML,这将非常理想

不幸的是,如果您需要任何上下文信息,比如“我想要标记
,但只有当它在标记
”中时,您必须自己维护它,因为解析器给您的只是“开始标记
,开始标记
,结束标记
,结束标记
”它从不明确地告诉您标签
在标签
内,您必须从您看到的内容中找出这一点。一旦你看到了一个元素,它就消失了,除非你自己记得它

对于复杂的解析工作来说,这会变得非常棘手,但您的任务可能是可以管理的


Python的标准库碰巧在
xml.SAX
中有一个SAX解析器。您可能需要类似于
xml.sax.xmlreader.IncrementalParser

的东西,您的初始算法运行在O(n^2)中,对于25GB的数据来说速度非常慢。理想情况下,您将把它归结为O(n)或O(n log n)。在没有关于数据的任何其他信息的情况下(如类别1或类别2是否更小等),您可以这样做(即O(n)):


虽然这不会解析您的文件,但希望它能向您展示这个想法。它可能会占用相当多的内存(因为它维护字典中的所有category1正文),因此这可能是一个考虑因素。

您的初始算法在O(n^2)中运行,对于25GB的数据,这将非常慢。理想情况下,您将把它归结为O(n)或O(n log n)。在没有关于数据的任何其他信息的情况下(如类别1或类别2是否更小等),您可以这样做(即O(n)):

虽然这不会解析您的文件,但希望它能向您展示这个想法。它可能会占用相当多的内存(因为它维护字典中的所有category1正文),因此这可能是一个考虑因素。

在当前在Saxon EE中实现的XSLT 3.0(草稿)中,您可以编写一个流式转换,解决此问题,如下所示:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:mode streamable="yes"/>
<xsl:template match="/">
  <xsl:iterate select="Document/Data">
    <xsl:param name="map" select="map{}"/>
    <xsl:choose>
      <xsl:when test="@category='1'">
        <xsl:next-iteration>
          <xsl:with-param name="map" select="map:put($map, string(@Id), string(@Body))"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="'Cat1 Body: ', 
                              $map(@CorrespondingCategoryId), 'Cat2 Body', @Body"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:template>

我还没有测试过这一点(这是在四天假期的前夜深夜…),但如果你有兴趣采用这种方法,我很乐意提供帮助。XSLT3.0仍然是一个草案规范,而且相当流畅。它的重点是使用流式处理方法解决类似这样的问题,该方法使用有限内存处理非常大的文档。Saxon EE 9.4实现了规范的快照。

在XSLT 3.0(草稿)中,正如当前在Saxon EE中实现的那样,您可以编写一个流式转换来解决此问题,如下所示:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map">
<xsl:mode streamable="yes"/>
<xsl:template match="/">
  <xsl:iterate select="Document/Data">
    <xsl:param name="map" select="map{}"/>
    <xsl:choose>
      <xsl:when test="@category='1'">
        <xsl:next-iteration>
          <xsl:with-param name="map" select="map:put($map, string(@Id), string(@Body))"/>
        </xsl:next-iteration>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="'Cat1 Body: ', 
                              $map(@CorrespondingCategoryId), 'Cat2 Body', @Body"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:iterate>
</xsl:template>


我还没有测试过这一点(这是在四天假期的前夜深夜…),但如果你有兴趣采用这种方法,我很乐意提供帮助。XSLT3.0仍然是一个草案规范,而且相当流畅。它的重点是使用流式处理方法解决类似这样的问题,该方法使用有限内存处理非常大的文档。Saxon EE 9.4实现了规范的快照。

如果ID按升序排列,那么您可以推出自己的函数来读取文件中任意位置的元素。然后,您可以扫描整个文件,对于每个元素,您可以使用二进制搜索算法找到相应的元素。它将在O(n log n)中运行,同时仍然使用可忽略不计的内存量。

如果ID按升序排列,那么您可以推出自己的函数来读取