2012-04-05 14 views
2

私の目的は、25GBのXMLデータを解析することです。このようなデータの例は以下の通りである:効率的な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"/> 

が、私は「25ギガバイト」の持っているデータをHowever..considering ...私のアプローチは非常に非効率的です。コードやその他の方法を改善する方法を提案してください。また、物事をより明確にするための小さなサンプルコードも含めてください。

+0

[Python saxとlxmlの80 + GB XMLの複製]可能性があります(http://stackoverflow.com/questions/9809469/python-sax-to-lxml-for-80gb-xml) –

答えて

4

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

SAXパーサーはDOMパーサーに比べて非常に高速でメモリ効率が良いことがあります。また、すべてのXMLを一度に指定する必要はありません。これは、25 GBのそれ。 「私は、タグ<B>をしたいが、それは、タグ<A>内だ場合にのみ、」すべてのパーサはあなたを与えるので、あなたは、それを自分で維持する必要がありますようにあなたは、どのようなコンテキスト情報が必要な場合

残念ながら、「タグ<B>を開始し、タグ<A>を開始しています終了タグ<B>、終了タグ<A>。 "タグ<B>がタグ<A>の内側にあると明示的には言わないので、あなたが見たものからそれを理解しなければなりません。一度要素を見たら、それを自分で覚えていない限り消えてしまいます。

これは複雑な解析ジョブでは非常に毛深くなりますが、おそらくあなたは管理しやすいでしょう。

Pythonの標準ライブラリでは、SAXパーサーがxml.saxになっています。おそらくxml.sax.xmlreader.IncrementalParserのようなものが欲しいでしょう。

+0

助けてくれてありがとう。小さなサンプルコードでそのコンセプトを説明してください...本当にあなたのようなものです...あなた自身の簡単な例も構築できます。 –

+0

私はチャンスを得たら私はします。しかし、私は時間があるだろうか分からない。 – kindall

0

私の最初の提案は、MySQLやsqliteなどのリレーショナルデータベースを使用することです。 XMLデータをこの形式に変換することは難しくありません。そのデータでクエリを実行すると、より簡単で高速になります。

+0

私はしたくないそのアプローチを取る...本質的に25GBのデータのためのテーブルの結合は、多くの時間がかかります。したがって、私はそれ自身を解析する代わりの方法を探しています –

+0

このたくさんのデータを使ってここで作成している種類のクエリについては、実際にはデータベースが必要です。インデックスを適切に定義すると、提案したものを行うよりもずっと速く簡単になります。そのため、SAXやその他のインクリメンタル・パーサーを使用してデータをデータベースにロードし、データベースからクエリを実行して新しいXMLファイルに書き出します。 –

0

初期アルゴリズムはO(n^2)で実行されますが、これは25GBのデータでは非常に遅くなります。理想的には、それをO(n)またはO(n log 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]) 

:(カテゴリー1または2が小さいか否かのような、など)データに関するその他の情報がない場合には、あなたは((n)はOである)このような何かを行うことができますあなたのファイルを解析し、うまくいけばそれはあなたにアイデアを示します。それは潜在的にかなりのメモリを使用します(辞書内のすべてのカテゴリ1のボディを維持しているため)。 XSLT 3.0(案)では

0

は、現在サクソン-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> 

私はそれがだ(これをテストしていません4日間の休日の夜、夜遅くに...)、この方法を追求することに興味があるなら、私は喜んでお手伝いします。 XSLT 3.0は依然としてドラフト仕様であり、かなり流動的です。その焦点は、境界のあるメモリを使用して非常に大きな文書を処理するストリーミングアプローチを使用して、このような問題を解決することにあります。 Saxon-EE 9.4は仕様のスナップショットを実装しています。

+0

これはかなり甘く見えます。 – kindall

0

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

0

lxmlからiterparseを試してみてください。私はそれがあなたが扱いたい問題に合うと思う。

+0

これは、同様の質問が.iterparse()によって解決されたものです。http://stackoverflow.com/a/9814580/1346705 – pepr

関連する問題