鴨川にあこがれる日々

軽い技術っぽい記事かいてます

wikipediaダンプデータのInsertが重かった時の話

はじめに

Wikipediaは,記事本文やリダイレクト情報など殆どの情報をダンプデータで公開しています.
Wikipedia:データベースダウンロード - Wikipedia

身の回りの研究では,

  • word2vecの学習データに記事本文を使う
  • Mecabの辞書を拡張するために見出し語を使う
  • 外部リンク解析の研究にリンクを使う

あたりを見る気がします.

今回たまたまページランクのようなものを計算しようとpagelinksのテーブルをダンプしてローカルのMysqlにインポートを試みましたが,全く終わらなかったので,その対処を書きます.


スキーマの概要などは古いですが,このサイトを参考にしました.

Wikipediaのダウンロードできるデータファイル一覧 | mwSoft

本題

jawiki-20141122-pagelinks.sqlというSQLファイルをそのままインポートすると2日かかっても終わりませんでした.
レコード数は約9000万強です.

スキーマをみると

CREATE TABLE `pagelinks` (
  `pl_from` int(8) unsigned NOT NULL DEFAULT '0',
  `pl_namespace` int(11) NOT NULL DEFAULT '0',
  `pl_title` varbinary(255) NOT NULL DEFAULT '',
  `pl_from_namespace` int(11) NOT NULL DEFAULT '0',
  UNIQUE KEY `pl_from` (`pl_from`,`pl_namespace`,`pl_title`),
  KEY `pl_namespace` (`pl_namespace`,`pl_title`,`pl_from`),
  KEY `pl_backlinks_namespace` (`pl_namespace`,`pl_title`,`pl_from_namespace`,`pl_from`)
) ENGINE=InnoDB DEFAULT CHARSET=binary;

とあります.

今回の用途では,データを使うだけです.
データを一旦インポートすれば,再度Insertもしないので,キー情報は不要です.

というわけで削除します.

activerecordの#find_eachメソッドは,primary keyがinteger型で昇順にできないと使えないっぽい*1です.
ActiveRecord::Batches

あとからIDを別途割り当てたいので,それも含めてキー情報を削除します



以下に書き換えます.

CREATE TABLE `pagelinks` (
  `pl_from` int(8) unsigned NOT NULL DEFAULT '0',
  `pl_namespace` int(11) NOT NULL DEFAULT '0',
  `pl_title` varbinary(255) NOT NULL DEFAULT '',
  `pl_from_namespace` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=binary;

インポートします.

$ mysql -ukamogawa -p hogehoge < jawiki-20141122-pagelinks.sql

すると30分かかりませんでした.見違える速さです.

RubyとかJavaで扱いたいのですが,pl_titleがvarbinaryで扱いが面倒なので,varcharに変換してしまいます.

CREATE TABLE `pagelinks` (
  `pl_from` int(8) unsigned NOT NULL DEFAULT '0',
  `pl_namespace` int(11) NOT NULL DEFAULT '0',
  `pl_title` varchar(255) NOT NULL DEFAULT '',
  `pl_from_namespace` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


primary keyの追加はこれで.

ALTER TABLE pagelinks ADD id INT PRIMARY KEY AUTO_INCREMENT;

以上.



2017年になっても2年前と同じようなことをしているわけなので,enwiki-2017****-page.sql をinsertしようとしたら同様の問題になった.
日本語と違って数GBから数十GBになるので,エディタで編集はできないのでheadとtailとかでDROPの行を消して以下のコマンドを先に実行してからsqlファイルを実行した.

CREATE TABLE `page` (
  `page_id` int(8) unsigned NOT NULL,
  `page_namespace` int(11) NOT NULL DEFAULT '0',
  `page_title` varchar(255) NOT NULL DEFAULT '',
  `page_restrictions` tinyblob NOT NULL,
  `page_counter` bigint(20) unsigned NOT NULL DEFAULT '0',
  `page_is_redirect` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `page_is_new` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `page_random` double unsigned NOT NULL DEFAULT '0',
  `page_touched` varchar(14) NOT NULL DEFAULT '',
  `page_links_updated` varchar(14) DEFAULT NULL,
  `page_latest` int(8) unsigned NOT NULL DEFAULT '0',
  `page_len` int(8) unsigned NOT NULL DEFAULT '0',
  `page_content_model` varchar(32) DEFAULT NULL,
  `page_lang` varchar(35) DEFAULT NULL
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

*1:違うようでしたら教えていただけると幸いです...