LoginSignup
39

More than 5 years have passed since last update.

Wikipediaの大量データをMySQLに保存する

Last updated at Posted at 2016-01-24

仕事でビッグデータとか機械学習周りの分野に手を出していきたい今日この頃なのですが、練習に業務用データを使うわけにもいきません。幸いWikipediaが全コンテンツを配布してくれているのでこのデータを取り込んでみました。

Wikipedia配布データの取得

Wikipediaのデータ配布については、サイト内の Wikipedia:データベースダウンロード ページに情報があります。

ここから配布先の ページに飛ぶと、各用途に応じてテキストファイル、XML、MySQLのダンプが配布されています。

今回はページ情報とカテゴリ・ページ間のリンク情報、ページ間のリンク情報を取得してみました。

ページ情報
jawiki-latest-page.sql.gz

カテゴリ間のリンク情報
jawiki-latest-categorylinks.sql.gz

ページ間のリンク情報
jawiki-latest-pagelinks.sql.gz

解凍

ダウンロードしたら解凍しておきます。
jawiki-latest-categorylinks.sql
jawiki-latest-pagelinks.sql
jawiki-latest-page.sql

MySQLへインポート

お手元のMySQLにログインして適当なdatabaseを準備します。

mysql> create database jawikipedia;

後は順次インポートしていくだけです。

$ mysql -u root jawikipedia < jawiki-latest-page.sql
$ mysql -u root jawikipedia < jawiki-latest-pagelinks.sql
$ mysql -u root jawikipedia < jawiki-latest-categorylinks.sql

データが大きくて実行時間は結構かかります。手元のMacでかかった大体の時間を参考までに載せておきます。
jawiki-latest-page.sql・・・数分で終わった。
jawiki-latest-pagelinks.sql・・・10分くらい。
jawiki-latest-pagelinks.sqlは・・・8時間くらい。途中PCがスリープになっていたので本当はもっと早かったかもしれません。

取り込んだデータ

テーブル構造

page

mysql> describe page;
+--------------------+---------------------+------+-----+---------+----------------+
| Field              | Type                | Null | Key | Default | Extra          |
+--------------------+---------------------+------+-----+---------+----------------+
| page_id            | int(8) unsigned     | NO   | PRI | NULL    | auto_increment |
| page_namespace     | int(11)             | NO   | MUL | 0       |                |
| page_title         | varbinary(255)      | NO   |     |         |                |
| page_restrictions  | varbinary(255)      | NO   |     |         |                |
| page_counter       | bigint(20) unsigned | NO   |     | 0       |                |
| page_is_redirect   | tinyint(1) unsigned | NO   | MUL | 0       |                |
| page_is_new        | tinyint(1) unsigned | NO   |     | 0       |                |
| page_random        | double unsigned     | NO   | MUL | 0       |                |
| page_touched       | varbinary(14)       | NO   |     |         |                |
| page_links_updated | varbinary(14)       | YES  |     | NULL    |                |
| page_latest        | int(8) unsigned     | NO   |     | 0       |                |
| page_len           | int(8) unsigned     | NO   | MUL | 0       |                |
| page_content_model | varbinary(32)       | YES  |     | NULL    |                |
+--------------------+---------------------+------+-----+---------+----------------+

Pageテーブルにはコンテンツは含まれていません。別途jawiki-latest-pages-articles.xml.bz2から取得する必要があります。 

categorylinks

mysql> describe categorylinks;
+-------------------+------------------------------+------+-----+-------------------+-----------------------------+
| Field             | Type                         | Null | Key | Default           | Extra                       |
+-------------------+------------------------------+------+-----+-------------------+-----------------------------+
| cl_from           | int(8) unsigned              | NO   | PRI | 0                 |                             |
| cl_to             | varbinary(255)               | NO   | PRI |                   |                             |
| cl_sortkey        | varbinary(230)               | NO   |     |                   |                             |
| cl_timestamp      | timestamp                    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| cl_sortkey_prefix | varbinary(255)               | NO   |     |                   |                             |
| cl_collation      | varbinary(32)                | NO   | MUL |                   |                             |
| cl_type           | enum('page','subcat','file') | NO   |     | page              |                             |
+-------------------+------------------------------+------+-----+-------------------+-----------------------------+

cl_fromがpage.page_idに対応します。

pagelinks

mysql> describe pagelinks;
+-------------------+-----------------+------+-----+---------+-------+
| Field             | Type            | Null | Key | Default | Extra |
+-------------------+-----------------+------+-----+---------+-------+
| pl_from           | int(8) unsigned | NO   | PRI | 0       |       |
| pl_namespace      | int(11)         | NO   | PRI | 0       |       |
| pl_title          | varbinary(255)  | NO   | PRI |         |       |
| pl_from_namespace | int(11)         | NO   | MUL | 0       |       |
+-------------------+-----------------+------+-----+---------+-------+

pl_fromがpage.page_idに対応します。

レコード数

取り込まれたレコード数です。pagelinksは取り込み途中の数値です。

mysql> select count(*) from page;
+----------+
| count(*) |
+----------+
|  2877211 |
+----------+
1 row in set (2.30 sec)

mysql> select count(*) from categorylinks;
+----------+
| count(*) |
+----------+
|  6382442 |
+----------+
1 row in set (6.97 sec)

mysql> select count(*) from pagelinks;
+-----------+
| count(*)  |
+-----------+
| 104787490 |
+-----------+
1 row in set (1 min 52.99 sec)

ページのカテゴリの一覧を取得する

mysql> select cl_to
    -> from categorylinks
    -> where cl_from in (
    ->   select page_id 
    ->   from page
    ->   where page_namespace=0
    ->     and page_title='機械学習'
    -> );
+-----------------------------------------+
| cl_to                                   |
+-----------------------------------------+
| サイバネティックス                      |
| 人工知能                                |
| 学習                                    |
| 機械学習                                |
| 解消済み仮リンクを含む記事              |
+-----------------------------------------+
5 rows in set (0.01 sec)

ページ内のリンクを取得する

mysql> select pl_namespace,pl_title
    -> from pagelinks
    -> where pl_from in (
    ->   select page_id 
    ->   from page
    ->   where page_namespace=0
    ->     and page_title='機械学習'
    -> );
+--------------+-----------------------------------------------------------+
| pl_namespace | pl_title                                                  |
+--------------+-----------------------------------------------------------+
|            0 | Apache_Mahout                                             |
|            0 | F検定                                                     |
|            0 | G検定                                                     |
|            0 | ID3                                                       |
|            0 | ISBN                                                      |
中略
+--------------+-----------------------------------------------------------+
244 rows in set (0.00 sec)

ページコンテンツをMySQLへ取り込む

注意:これ以降は最終的に失敗しています。

ページのコンテンツは、jawiki-latest-pages-articles.xml.bz2 にあるのですが、巨大なXMLファイルで扱いが難しいです。GroovyのXmlSlurperでパースしてみましたが、あえなくOutOfMemoryError.になりました。(SAXなのになぜ?)

コンテンツ
jawiki-latest-pages-articles.xml.bz2

コンテンツを分割したもの?
jawiki-latest-pages-articles1.xml.bz2
jawiki-latest-pages-articles2.xml.bz2
jawiki-latest-pages-articles3.xml.bz2
jawiki-latest-pages-articles4.xml.bz2

「Wikipedia:データベースダウンロード」ページにはxml2sqlというツールへのリンクがあるのでそれを試してみます。

xml2sqlのダウンロード

上記リンク先から、さらにGitHubのぺージへ飛びます。

https://github.com/Tietew/mediawiki-xml2sql からプロジェクトをgit cloneします。

make

クローンしたプロジェクト内のINSTALLファイルに手順があります。

./configure
make
sudo make install

INSTALLファイルには、UNIX、Linux、Windowsに対しての説明が書いてありますが、Macでもビルドできました。

成功するとxml2sqlコマンドが作成されます。
/usr/local/bin/xml2sql

実行してみる

cat jawiki-latest-pages-articles.xml |  xml2sql -m 
unexpected element <dbname>
xml2sql: parsing aborted at line 4 pos 12.

dbnameエレメントが認識できずにエラーになります。もともとxml2sqlは、英語版用でja.wikipeditaは対象外なのかもしれません。orz...

試しにエラーになるタグを片っ端からスキップしてみます。

cat jawiki-latest-pages-articles.xml | grep -v "<dbname>"
 | grep -v "<ns>" | grep -v "<parentid>" | grep -v "<model>"
 | grep -v "<format>" | grep -v "<sha1>" | grep -c "<redirect>" | xml2sql -m

(実際は1行です。拙いgrepですみません。)

実行結果

   587  1 25 00:07 page.sql
     0  1 24 23:23 page.txt
   573  1 25 00:07 revision.sql
     0  1 24 23:23 revision.txt
113207  1 25 00:07 text.sql
     0  1 24 23:23 text.txt

何やらファイルが作られますが、しばらくたってもファイルサイズが大きくならず、応答もないままになりました。上手く動作していないようです。

今回はここで諦めます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39