読者です 読者をやめる 読者になる 読者になる

望月いちろうのREADME.md

書き溜めておいた技術記事や旅行記のバックアップです。

wikipediaのdumpデータをデータベースに格納する - SAXを利用する

機械学習の勉強をしているとモデルの性能を試すのにテストデータが必要になることがあります。そのような用途を考えてかwikipediaは公式にdumpデータを提供しています。このデータはプレーンテキストのファイルでxml形式で提供されています。実際に分析を行う場合にはこれをデータベースに格納してから使うのが最適なのですが1つ問題があります。それはdumpデータの容量が大きすぎて普通のxmlパーサーではメモリーに乗り切らないエラーが発生することがあることです。今回はこの問題への対処法を解説したいと思います。

xmlパーサーの規格を確認する

大別してxmlパーサーには2種類の形式があります。それはDOM型とSAX型です。Web開発をしている方であればDOMという言葉を聞いたことがあると思います。DOMとはDocument Object Modelの略で、xmlデータの構造(一般にDOMツリーと呼ぶ)を保持してデータを読み込みます。複雑な構造をしたxmlファイルを解析するには便利な方法ですが、このタイプのxmlパーサーは一度すべてのxmlデータをメモリにマウントする必要があるので大きなxmlファイルを読み込むことが困難になります。

ここで必要になるのはSAX(Simple API for XML)です。SAX型のパーサーはxmlデータを上から順番に1行ずつ読み込みます。非常に原始的な方法ですが、これだと前述のメモリ容量の問題はほとんど解決されることになります。

今回はPythonxmlライブラリからSAX型のパーサーを利用してwikipediaのdumpデータをMongoDBに格納するデモを実行してみようと思います。通常のインストールであればxmlライブラリはデフォルトで使用できるはずです。

では実際に動作するコードを見てみたいと思います。

コード

import sys
import xml.sax
import pymongo
import re
from xml.sax.handler import ContentHandler

db = pymongo.MongoClient("mongodb://localhost:27017/").wikipedia.pages

class SAX_handler(ContentHandler):

    def __init__(self, writer=sys.stdout):

        self._writer = writer
        self._node = []
        self._obj = {}
        self._item = ""
        self._cursor = ""
        ContentHandler.__init__(self)

    def startElement(self, name, attrs):

        self._cursor = name

    def endElement(self, name):

        self._obj[self._cursor] = self._item
        # reset
        self._item = ""  
        if name == "page":
           print(self._obj)
           db.insert_one(self._obj)
           self._obj = {}

    def characters(self, data):
        self._item += data.strip() 

parser = xml.sax.make_parser()
parser.setContentHandler(SAX_handler())
parser.parse("./jawiki")

重要な箇所

parser.parseで解析対象のxmlファイルのパスを指定します。これは同一フォルダ内のjawikiを解析の対象にする例です。

parser.parse("./jawiki")

ローカルで起動中のMongoDBインスタンスwikipediaデータベースのpagesコレクションにデータを格納することを指定しています。

db = pymongo.MongoClient("mongodb://localhost:27017/").wikipedia.pages

注意点

SAX型のパーサーは脆弱性があるのでWebアプリケーションには使用すべきではありません。詳しくは公式ページ

https://docs.python.org/2/library/xml.html#xml-vulnerabilities

を見てください。