2

私の目標は、25 GB の 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"/>

ただし、「25 GB」のデータを考慮すると、私のアプローチは非常に非効率的です。私のコードまたは別のアプローチを改善する方法を提案してください。また、わかりやすくするために小さなコード例を含めてください。

4

6 に答える 6

4

このタスクには、SAX パーサーの方が適している場合があります。SAX パーサーは、DOM を構築するのではなく、XML ファイルを要素のストリームに変換し、提供された関数を呼び出して、各要素を処理できるようにします。

良い点は、SAX パーサーは DOM パーサーに比べて非常に高速でメモリ効率が高く、一部のパーサーはすべての XML を一度に与える必要がないことです。これは、25 GB のパーサーがある場合に理想的です。

残念ながら、「タグ<B>が必要だがタグ内にある場合のみ」などのコンテキスト情報が必要な場合<A>は、パーサーが提供するのは「開始タグ<A>、開始タグ<B>、終了タグ<B>、終了タグ」だけであるため、自分で維持する必要があります<A><B>tagが tag 内にあることを明示的に伝えることはありませ<A>ん。見たものからそれを理解する必要があります。そして、要素を見たら、自分で覚えていない限り、それは消えてしまいます。

これは複雑な解析ジョブでは非常に面倒ですが、おそらくあなたのものは扱いやすいでしょう。

Python の標準ライブラリに SAX パーサーが含まれていることがありxml.saxます。おそらく次のようなものが必要ですxml.sax.xmlreader.IncrementalParser

于 2012-04-05T19:48:16.427 に答える
0

最初のアルゴリズムはO(n ^ 2)で実行されますが、25GBのデータでは非常に遅くなります。理想的には、O(n)またはO(n log n)になります。データに関する他の情報がない場合(カテゴリ1または2が小さいかどうかなど)、次のように実行できます(O(n))。

from lxml import objectify
f=open('myfile25GB', 'r')
text=f.read()
root=objectify.fromstring(text)

cat_one_bodies = {}
for e in root.attrib['Document'].row:
    category = int(e.attrib['category'])
    body = e.attrib['Body']
    if category == 1:
        e_id = int(e.attrib['Id'])
        cat_one_bodies[e_id] = body
    else: #Assuming there are only 2 categories
        cat_one_id = int(e.attrib['CorrespondingCategory1Id'])
        print "Cat1 Body: '%s' Cat2 Body: '%s'" % (body, cat_one_bodies[cat_one_id])

これはファイルを解析しませんが、うまくいけば、それはあなたにアイデアを示します。(ディクショナリ内のすべてのcategory1本体を維持しているため)かなりのメモリを使用する可能性があるため、考慮事項になる可能性があります。

于 2012-04-05T20:04:11.783 に答える
0

現在 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>

私はこれをテストしていません (4 連休の前夜の深夜です...) が、このアプローチを追求することに興味がある場合は、喜んでお手伝いします。XSLT 3.0 はまだドラフト仕様であり、かなり流動的です。その焦点は、制限されたメモリを使用して非常に大きなドキュメントを処理するストリーミング アプローチを使用して、このような問題を解決することにあります。Saxon-EE 9.4 では、仕様のスナップショットが実装されています。

于 2012-04-05T22:19:44.833 に答える
0

ID が昇順の場合、ファイル内の任意の位置にある要素を読み取る独自の関数をロールアウトできます。次に、ファイル全体をスキャンするだけで、すべての要素について、バイナリ検索アルゴリズムを使用して対応する要素を見つけることができます。ごくわずかな量のメモリを使用しながら、O(n log n) で実行されます。

于 2012-04-05T22:32:18.043 に答える
0

lxml から iterparse を試してみてください。扱いたい問題に合うと思います。

于 2012-05-08T11:53:24.447 に答える