プログラマでありたい

おっさんになっても、プログラマでありつづけたい

wikipediaのダウンロード&データベースにインポート

ダウンロード

Wikipedia:データベースダウンロード
ウィキペディア日本語版:

jawiki-latest-pages-meta-current.xml.bz2

xml2sqlでmysqldump形式に変換

 wikipediaのコンテンツは、600MB以上ある。それなりに時間が掛かるので、落としている間にデータベースへのインポートの準備。データの提供形態はxmlなので、データベースに入れるにはそれなりの工夫が必要である。幸いwikipedia自体が2種類の方法を提供してくれている。MediaWikiに付属しているimportDump.phpを使うか、xml2sqlというツールをインストールするかが選べる。
 他でも使えそうなので、xml2sqlを使うことにした。
xml2sql

$wget ftp://ftp.tietew.jp/pub/wikipedia/xml2sql-0.5.tar.gz
$tar xzvf xml2sql-0.5.tar.gz
$cd xml2sql-0.5
$./configure
$make
$sudo make install

xml2sqlを使ってxmlをmysqldump形式に変換。

$bunzip2 -c jawiki-latest-pages-meta-current.xml.bz2 | xml2sql 

2.5GB位のtext.txtと、80MB程度のrevision.txt,page.txtが出来る。

ちなみにxml2sqlのオプションは以下の通り。-iがデフォルトで、mysqldumpのフォーマットで出力してくれる。

Options
-i, --import 	mysqlimport format. (default)
Output filenames are page.txt, revision.txt, and text.txt. You can use mysqlimport program to import this format.
-m, --mysql 	MySQL's INSERT format.
Output filenames are page.sql, revision.sql, and text.sql. You can use mysql program to import this format.
-p, --postgresql[=version] 	PostgreSQL's COPY format.
Output filenames are page.sql, revision.sql, and text.sql. If the version is omitted, 8.0 and earlier is assumed. You can use psql program to import this format.
-c, --compress[={old,full}] 	Compress text table with deflate. (default: old)
When output format is postgresql, this option is ignored because PostgreSQL will compress table data itself.
-r, --renumber 	Renumber page id and revision id.
-N, --namespace=ns,ns,... 	Output only specifig namespaces. Namespaces can be specified by both namespace number and namespace name.
-t, --no-text 	Exclude text table
-o, --output-dir=OUTDIR 	Specifies output directory (default: current directory)
-t, --tmpdir=TMPDIR 	Specifies temporary directory (default: OUTDIR)
Temporary file is used only if --compress=old.
-v, --verbose 	Show progress
-h, --help 	Display help and exit
--version 	Display version information and exit

データベースの準備

 残念ながらテーブル作成のSQLまでは作ってくれないので、自前でテーブルを作成する。tables.sqlのページに必要なDDLが書いてある。今回必要なのは、page,revision,textの3つのテーブルだけ。(コーパスと言う意味では、textだけだが。)

create database corpus;
use corpus;

CREATE TABLE page (
  page_id int unsigned NOT NULL auto_increment,
  page_namespace int NOT NULL,
  page_title varchar(255) binary NOT NULL,
  page_restrictions tinyblob NOT NULL,
  page_counter bigint unsigned NOT NULL default '0',
  page_is_redirect tinyint unsigned NOT NULL default '0',
  page_is_new tinyint unsigned NOT NULL default '0',
  page_random real unsigned NOT NULL,
  page_touched binary(14) NOT NULL default '',
  page_latest int unsigned NOT NULL,
  page_len int unsigned NOT NULL,

  PRIMARY KEY page_id (page_id),
  UNIQUE INDEX name_title (page_namespace,page_title),
  
  -- Special-purpose indexes
  INDEX (page_random),
  INDEX (page_len)
);

CREATE TABLE revision (
  rev_id int unsigned NOT NULL auto_increment,
  rev_page int unsigned NOT NULL,
  rev_text_id int unsigned NOT NULL,
  rev_comment tinyblob NOT NULL,
  rev_user int unsigned NOT NULL default '0',
  rev_user_text varchar(255) binary NOT NULL default '',
  rev_timestamp binary(14) NOT NULL default '',
  rev_minor_edit tinyint unsigned NOT NULL default '0',
  rev_deleted tinyint unsigned NOT NULL default '0',
  rev_len int unsigned,
  rev_parent_id int unsigned default NULL,

  PRIMARY KEY rev_page_id (rev_page, rev_id),
  UNIQUE INDEX rev_id (rev_id),
  INDEX rev_timestamp (rev_timestamp),
  INDEX page_timestamp (rev_page,rev_timestamp),
  INDEX user_timestamp (rev_user,rev_timestamp),
  INDEX usertext_timestamp (rev_user_text,rev_timestamp)

)  MAX_ROWS=10000000 AVG_ROW_LENGTH=1024;

CREATE TABLE text (
  old_id int unsigned NOT NULL auto_increment,
  old_text mediumblob NOT NULL,
  old_flags tinyblob NOT NULL,
  
  PRIMARY KEY old_id (old_id)

) MAX_ROWS=10000000 AVG_ROW_LENGTH=10240;

データのインポート

準備が整ったので、いよいよデータのインポート

mysqlimport -u username corpus /dir/data/*.txt

エラーが出た。pageテーブルがuniq制約で引っ掛かってるとのこと。なんでやねん。

mysqlimport: Error: Duplicate entry '0-辰' for key 2, when using table: page

他の二つのテーブルは問題なく上手くいくので、とりあえずuniq制約を外してインポートしてみる。
無事成功。どのレコードが問題なのか調べてみる。

select page_namespace,page_title,count(*) from page group by page_namespace,page_title having count(*) > 1;
+----------------+------------+----------+
| page_namespace | page_title | count(*) |
+----------------+------------+----------+
|              0 |            |        2 |
|              0 | 辰         |        2 |
|              2 |            |        2 |
+----------------+------------+----------+
3 rows in set (10.60 sec)

放置決定。これにて、データベースへのインポートは終了。次は、これからコーパスの作成へ