【少しずつ追記】XMLデータベース「BaseX」のインストールからベンチマークまで

More than 3 years have passed since last update.


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の例です。


/etc/yum.repos.d/basex.repo

[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クライアントを起動。

Spectacle.GzU947.png

素敵な画面が出てきました。これがあれば開発も楽そう。

ん?

これ、リモートの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の手抜きなサンプル。

(手を抜いてないサンプルは、上記のリンクからもダウンロードできます)


sample.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