#XMLデータベース「BaseX」のインストールからベンチマークまで
##前書き
がっつり正規化されたRDBMSでテーブルの山を見て嫌になっちゃいました。
階層化されたデータを表現するために、親IDを格納するカラムを作って、再帰的に親や子を探すのにも疲れちゃいました。
大体そういうデータはRDBMSには向いてません。ドキュメントベースでスキーマレスなデータベースで行きましょう。
ドキュメントベースのDBとして私が思いついたのは、
- XML が基本となる「BaseX」
- JSON が基本となる「mongo」
あたりでしょうか。どちらもオープンソースです。
プロプライエタリなものでスッゴイものもあると思いますが、貧乏なのでお金がかけれません。
しかし、私の探し方が悪いのか、何故かどちらも日本語のドキュメントが少ない。
今回は「BaseX」に挑戦してみます。
構築しながら、ハりそうな(ハマった)ところなんかもメモしていければと思います。
-- 2016-01-19 23:27
##インストール
私の環境はArch Linux なので、一発です。
yaourt -S basex
多分、Ubuntu、Debian なんかも
apt-get install basex
でいけるんでないでしょうか。試してません。
Fedora、CentOS あたりは、yum のリポジトリを追加しないといけないかもしれません。
CentOS6 の時は追加しないといけませんでした。
以下のような内容のファイルを /etc/yum.repos.d/base.repo みたいな感じで作成します。
Fedora22の例です。
[home_basex_opensuse]
name=BaseX openSUSE Build (Fedora_22)
type=rpm-md
baseurl=http://download.opensuse.org/repositories/home:/basex:/opensuse/Fedora_22/
gpgcheck=1
gpgkey=http://download.opensuse.org/repositories/home:/basex:/opensuse/Fedora_22//repodata/repomd.xml.key
enabled=1
本家のサイトのダウンロードのページからコピってきました。Fedora23のリポジトリは書いてありませんでした。しかしなんで Suse なんだろう?
作成したら、
yum install basex
で、多分いけると思います。
インストールされるバイナリが、 9.92MB ! ちっちゃいなぁ…。
BaseX はJava で書いてありますので、依存関係でJava がインストールされるかもしれません。
あれ?起動方法がわかんない。
-- 2016-01-19 23:44
##起動
CentOS の場合、/usr/bin 以下にインストールされています。
Arch Linux の場合、/usr/share/java/basex/bin にインストールされていました。
というかGUIのメニューに basexgui が登録されていました。
コマンド | 内容 |
---|---|
basex | スタンドアロンの対話モードで実行 |
basexgui | GUIのクライアント |
basexclient | Client/Server モードのクライアント |
basexserver | Client/Server モードのサーバ |
basexserverstop | サーバで起動したbasexを停止 |
basexhttp | よくわかんないので今度にする |
basexhttpstop | http で起動したbasexを停止(多分) |
まずは素直にメニューからGUIクライアントを起動。
素敵な画面が出てきました。これがあれば開発も楽そう。
ん?
これ、リモートのbasexサーバに繋げないのかな?
あとで考える。
スタンドアロンの対話モードもOK。
サーバの起動は、
/path/to/basex/bin/basexserver -S
ポートは1984がデフォルト。起動時に-pオプションで変えられるようです。
その他のオプションは--helpで。
起動スクリプトなど気の利いたものは用意されていません。
systemd の起動スクリプト書くのもめんどいので、/etc/rc.local に起動コマンドを書いて、rc.local のエグゼキュートビットを有効に設定。
これでOS起動時に自動的にサービスが起動するはず。
クライアントで接続してみる。ローカルホストなら省略できますが、
/path/to/basex/bin/basexclient -n localhost
パスワードが聞かれた。そんなの知らんぞ…。
http://docs.basex.org/wiki/Startup#Client.2FServer
ちゃんと書いてありました。
Username: admin
Password: admin
です。
しかし、あぶねぇパスワード。変えておきましょう。
ログインしたあとに、
> PASSWORD
一旦ここまでで、再起動してみます。
-- 2016-01-20 00:52
起動成功。今日はもう眠い。続きは明日。
-- 2016-01-20 00:59
##CREATE DB してみる
basexclient でローカルホストの basex サーバに接続して新規のデータベースを作成してみる。
> CREATE DB testdb
> XQUERY /
Stopped at ., 1/2:
[XPDY0002] root(): no context value bound.
ありゃ?
あぁ、ちゃんとOPENしないとダメでした。
> OPEN testdb
Database 'testdb' was opened in 1.48 ms.
> XQUERY /
Query executed in 0.3 ms.
次にデータを突っ込んでみる。
いきなりつまずいたが、データを突っ込むには先ほど作成したデータベース「testdb」の中にxmlを作らないといけないらしい。
> ADD TO sample1.xml "<root/>"
Resource(s) added in 71.61 ms.
> LIST testdb
Input Path Type Content-Type Size
----------------------------------------
sample1.xml xml application/xml 2
Resources.
> XQUERY /
<root/>
Query executed in 0.55 ms.
出た。でも xml は指定してないぞ?
> ADD TO sample2.xml "<root2/>"
Resource(s) added in 6.98 ms.
> LIST testdb
Input Path Type Content-Type Size
----------------------------------------
sample1.xml xml application/xml 2
sample2.xml xml application/xml 2
Resources.
> XQUERY /
<root/>
<root2/>
Query executed in 1.16 ms.
なるほど。カレントのDB内のxmlすべてが検索対象なのね。
> XQUERY doc("testdb/sample1.xml")/root
<root/>
こうすれば、特定の xml ファイルに対して XQUERY が発行される。
DB名は省略できないらしい。めんどくさい。
OPENしていない状態でも実行可能。
ちょっと削除してみよう。
> DELETE /
0 resource(s) deleted in 1.76 ms.
> xquery /
Query executed in 0.35 ms.
>
> LIST testdb
Input Path Type Content-Type Size
------------------------------------
Resources.
ぎゃーーーー。全部消えた!
DELETE 、これは恐ろしいコマンドだ…。
くじけてしまったので、一旦 basexclient から抜ける。
ところでBaseXのファイルはどこにあるんだろう?
/root/BaseXData にあった。
実行したユーザのホームディレクトリにできるようだ。
そのディレクトリに下にDB名のディレクトリが作成され、その中には *.basex のファイルがあるけどバイナリのようだ。
これDBがでかくなったらどうなるんだろう?
それから、私のOSの場合、/root のファイルシステムはBtrfsなのだが、CoWの影響も気になる。
ま、でかいDB作ったあとでCoWを無効にして試してみよう。
少ししか試せなかったけど今日はここまで。
ベンチマークに使えそうな巨大な xml ファイルを探してこよう。
-- 2016-01-21 01:22
##データ投入
速度を測るにもデータをぶち込まなければ始まらない。
巨大なのxmlをダウンロードして来てぶち込んでみます。
その前にPCスペックは、
CPU Core i7-3930K 3.20GHz
メモリ 32GB
ディスク /root/BaseXData がある領域は、SSD 2台を Btrfs で RAID0 構成
インポートするファイルは、wikipedia のYahoo向けabstract、1.7GB
> add to wiki.xml /tmp/jawiki-20160111-abstract.xml
Resource(s) added in 102797.21 ms.
> XQUERY count(/feed/doc)
1603475
Query executed in 384.85 ms.
ほう、意外と速い。
検索してみる。
> xquery count(feed/doc/title[contains(text(),'ガンダム')])
1179
Query executed in 2191.71 ms.
キーワードについては見逃してください。そんな世代なんです。
BaseX はJava で書かれているので、日本語もばっちり。
インデックスを作ってみる。
> CREATE INDEX TEXT
Index 'TEXT' created in 24116.67 ms.
> xquery count(feed/doc/title[contains(text(),'ガンダム')])
1179
Query executed in 2122.68 ms.
あんましかわらん。私が想像してるインデックスとは別物なのか。
> CREATE INDEX FULLTEXT
Out of Main Memory.
うぎゃー。
ちなみに実ファイルの方は、
-rw-r--r-- 1 root root 25M 1月 21 02:34 atv.basex
-rw-r--r-- 1 root root 4 1月 21 00:23 atvl.basex
-rw-r--r-- 1 root root 0 1月 21 00:23 atvr.basex
-rw-r--r-- 1 root root 628 1月 22 00:01 inf.basex
-rw-r--r-- 1 root root 11 1月 21 02:34 pth.basex
-rw-r--r-- 1 root root 28 1月 21 23:59 swl.basex
-rw-r--r-- 1 root root 795M 1月 21 02:34 tbl.basex
-rw-r--r-- 1 root root 1.6M 1月 21 02:34 tbli.basex
-rw-r--r-- 1 root root 1.3G 1月 21 02:34 txt.basex
-rw-r--r-- 1 root root 43M 1月 21 23:58 txtl.basex
-rw-r--r-- 1 root root 29M 1月 21 23:58 txtr.basex
Btrfs の CoW を無効にしてみました。
# mv BaseXData BaseXData_old
# mkdir BaseXData
# chattr +C BaseXData
# cp -a BaseXData_old/* BaseXData
> xquery count(feed/doc/title[contains(text(),'ガンダム')])
1179
Query executed in 1827.73 ms.
少し早くなった。
もっと複雑な検索も試してみたいとこなのですが、結構いけるんではないでしょうか?
しかし、XQuery、XPathは難しいなぁ…。
-- 2016-01-22
##PHPから接続してみる
PHPから接続するには、BaseXのClientsのページからBaseXClients.php をダウンロードしておきます。
で、PHPの手抜きなサンプル。
(手を抜いてないサンプルは、上記のリンクからもダウンロードできます)
<?php
// クラス定義ファイルのインクルード
include_once("./BaseXClient.php");
// DBへの接続とデフォルトDBのオープン
$session = new Session("localhost", 1984, "username", "password");
$session->execute("OPEN testdb");
// クエリの発行
$input_xpath = "feed/doc/title[contains(text(),'ガンダム')]/text()";
$input_flwor = "for \$i in feed/doc/title where contains(\$i/text(), 'ガンダム') return \$i/text()";
$query = $session->query($input_flwor);
// データの表示
while($query->more()) {
print $query->next() . "\n";
}
// クエリとDB接続のクローズ
$query->close();
$session->close();
クラス名がSession とか、xquery 内で改行が使えないとか、気に入らないところも…。
まぁラッパー作っちゃえばいいんですが。
あと、クラスの中でsocketが使われているので、PHP がsocket オプション付きでインストールされている必要がありそうです。
とりあえずここまで行けたら、必要なデータをxml とJSON とSQL でファイル出力していろいろ比較できそう。
-- 2016-01-24 23:12