« setlock を使って cron をぶんまわす方法 | メイン | Range Coder の終了処理 »

2008年02月05日

Tritonn (MySQL+Senna) の join を高速化

 自分の利用形態において、Tritonn の処理を最適化するパッチを書きました。具体的には、2種類の最適化を行いました。ひょっとするとバグがあるかもしれませんが、興味がある方は、以下のパッチ (tritonn-1.0.9用) とあわせてごらんください。

tritonn-embed-primary-key-v3.patch

1. 全文索引内にプライマリキーを格納

 SQL クエリを最適化する際、アクセスしたい全カラムを格納したインデックスを作成することで行データへのアクセスを抑止して速度を稼ぐ、というのは定石のひとつです。しかし、MySQL の全文索引 (フルテキストインデックス) では、他のカラムと組み合わせた複合キーを作成することができません。このことが、Tritonn の全文索引を他のテーブルと結合したい場合に問題となっていました。

 そこで、プライマリキーを全文索引に追加するようなパッチを作りました。これにより、全文索引でマッチしたプライマリキーをすべて取り出す (そして結合する) というようなユースケースにおいて行データへのアクセスが発生しなくなり、2倍から8倍程度の速度向上を果たしています。これは同時に、このような場合において行データをオンメモリに保っておく必要がなくなったということであり、実質的に従来の倍程度のデータセットを取り扱えるようになったことを意味します。

 また、従来 2ind patch を用いていたようなケースにおいても、速度が向上する場合があるようです。これは、2ind patch が、force index されたカラムを利用して逐次全文索引を参照するのに対して、拙作のパッチを用いると、その逆順で条件に合致する行を取り出し、ソートすることが可能なためです。つまり、頻出語においては、2ind patch が有利になり、頻度が低くなれば拙作のパッチが有利になります。

#「test」で検索した結果を編集日時でソート (2ind)
mysql> select id,mtime,left(body,16) from tbl_2ind force index (mtime) where match(body) against ('+test' in boolean mode) order by mtime desc limit 10;
(snip)
10 rows in set (0.01 sec)

#「test」で検索した結果を編集日時でソート (embedded_pkey)
mysql> select t3.id,t3.mtime,left(t4.body,16) from (select t1.id,t2.mtime from tbl_embedded as t1 inner join tbl as t2 use index (id_mtime) on t1.id=t2.id where match(t1.body) against ('+test' in boolean mode) order by t2.mtime desc limit 10) as t3 inner join tbl as t4 on t3.id=t4.id;
(snip)
10 rows in set (0.04 sec)

#「captcha」で検索した結果を編集日時でソート (2ind)
mysql> select id,mtime,left(body,16) from tbl_2ind force index (mtime) where match(body) against ('+captcha' in boolean mode) order by mtime desc limit 10;
(snip)
10 rows in set (0.13 sec)

#「captcha」で検索した結果を編集日時でソート (embedded_pkey)
mysql> select t3.id,t3.mtime,left(t4.body,16) from (select t1.id,t2.mtime from tbl_embedded as t1 inner join tbl as t2 use index (id_mtime) on t1.id=t2.id where match(t1.body) against ('+captcha' in boolean mode) order by t2.mtime desc limit 10) as t3 inner join tbl as t4 on t3.id=t4.id;
(snip)
10 rows in set (0.00 sec)

 本機能を利用するには、my.cnf に senna_embedded_pkey=1 と設定した上で CREATE TABLE 文を実行します。本機能の副作用として、2ind patch が有効な状況下において、セカンダリキーを force index した状態において全文索引を利用する場合に、必ず行データへのアクセスが発生するようになります (セカンダリキーからの行データ読込の最適化を抑止している) ので、そのような使い方と併用したい場合は、テーブル分割をご検討ください。

2. 単語の出現頻度によるスコア計算

 boolean mode での全文検索において単語の出現回数が返ってきているようだったので、単語の出現回数をカラムの長さで割った値を返すようにしました。本機能を利用するには、パッチをあてた Tritonn を -DENABLE_SENNA_PSEUDO_TF した上で make し、 my.cnf に senna_pseudo_tf=1 と設定した上で CREATE TABLE 文を実行します。

投稿者 kazuho : 2008年02月05日 14:58 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1758