3

MongoNYC 2013 カンファレンスで、講演者はウィキペディアのコピーを使用して全文検索をテストしたと述べました。私はこれを自分で複製しようとしましたが、ファイルのサイズと形式が原因で自明ではないことがわかりました.

これが私がやっていることです:

$ wget http://download.wikimedia.org/enwiki/latest/enwiki-latest-pages-articles.xml.bz2
$ bunzip2 enwiki-latest-pages-articles.xml.bz2 
$ python
>>> import xml.etree.ElementTree as ET
>>> tree = ET.parse('enwiki-latest-pages-articles.xml')
Killed

標準の XML パーサーで XML ファイルを解析しようとすると、XML ファイルのサイズで Python エラーが発生します。9GBのXMLファイルをmongoDBにロードできるJSON-yに変換する方法について、他に提案はありますか?

更新 1

以下のショーンの提案に従って、反復要素ツリーも試しました。

>>> import xml.etree.ElementTree as ET
>>> context = ET.iterparse('enwiki-latest-pages-articles.xml', events=("start", "end"))
>>> context = iter(context)
>>> event, root = context.next()
>>> for i in context[0:10]:
...     print(i)
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_IterParseIterator' object has no attribute '__getitem__'
>>> for event, elem in context[0:10]:
...     if event == "end" and elem.tag == "record":
...             print(elem)
...             root.clear()
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_IterParseIterator' object has no attribute '__getitem__'

同様に、運もありません。

更新 2

以下の Asya Kamsky の提案をフォローアップします。

ここで試していxml2jsonます:

$ git clone https://github.com/hay/xml2json.git
$ ./xml2json/xml2json.py -t xml2json -o enwiki-latest-pages-articles.json enwiki-latest-pages-articles.xml
Traceback (most recent call last):
  File "./xml2json/xml2json.py", line 199, in <module>
    main()
  File "./xml2json/xml2json.py", line 181, in main
    input = open(arguments[0]).read()
MemoryError

ここにありxmlutilsます:

$ pip install xmlutils
$ xml2json --input "enwiki-latest-pages-articles.xml" --output "enwiki-latest-pages-articles.json"
xml2sql by Kailash Nadh (http://nadh.in)
    --help for help


Wrote to enwiki-latest-pages-articles.json

しかし、中身はただの1枚。それは繰り返されませんでした。

xmltodict、繰り返し Expat を使用し、ウィキペディアに適していることを宣伝しているため、有望に見えました。しかし、これも 20 分ほどでメモリ不足になりました。

>>> import xmltodict
>>> f = open('enwiki-latest-pages-articles.xml')
>>> doc = xmltodict.parse(f)
Killed

更新 3

これは、以下のロスの回答への回答であり、彼が言及したリンクから私のパーサーをモデル化しています。

from lxml import etree

file = 'enwiki-latest-pages-articles.xml'

def page_handler(page):
    try:
        print page.get('title','').encode('utf-8')
    except:
        print page
        print "error"

class page_handler(object):
    def __init__(self):
        self.text = []
    def start(self, tag, attrib):
        self.is_title = True if tag == 'title' else False
    def end(self, tag):
        pass
    def data(self, data):
        if self.is_title:
            self.text.append(data.encode('utf-8'))
    def close(self):
        return self.text

def fast_iter(context, func):
    for event, elem in context:
        print(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

process_element = etree.XMLParser(target = page_handler())

context = etree.iterparse( file, tag='item' )
fast_iter(context,process_element)

エラーは次のとおりです。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fast_iter
  File "iterparse.pxi", line 484, in lxml.etree.iterparse.__next__ (src/lxml/lxml.etree.c:112653)
  File "iterparse.pxi", line 537, in lxml.etree.iterparse._read_more_events (src/lxml/lxml.etree.c:113223)
  File "parser.pxi", line 596, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:83186)
lxml.etree.XMLSyntaxError: Extra content at the end of the document, line 22, column 1
4

2 に答える 2

1

iterparseファイル全体をメモリにロードするのではなく、反復するために使用する必要があります。json または db に格納するための python オブジェクトに変換する方法については、https ://github.com/knadh/xmlutils.py/blob/master/xmlutils/xml2json.py を参照してください。

アップデート

iterparse を使用して低いメモリ フットプリントを維持する例:

Liza Daly の fast_iter のバリアントを試してください。要素を処理した後elem、 を呼び出しelem.clear()て子孫を削除し、前の兄弟も削除します。

from lxml import etree

def fast_iter(context, func):
    # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    # Author: Liza Daly
    for event, elem in context:
        print(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

context = etree.iterparse( MYFILE, tag='item' )
fast_iter(context,process_element)

特に大きな XML ファイルを処理している場合は、Daly の記事を読むとよいでしょう。

于 2013-06-25T14:35:31.823 に答える