mysql4.0系でfulltextを利用したマルチバイト全文検索2

前回の続き

とりあえず強引に mysql4.0系でマルチバイト対応全文検索してみるだけ。
簡単に言えばトークンに切り出して、それをmd5して別テーブルに格納するという力ワザ。

どうやってトークンを切りだすか

以前流行った正規表現ベースのトークンとn-gramで速度比較

100文字ほどのデータだと
%php -f morph.php  ←正規表現ベース
0.0232629776001sec
%
%php -f ngram.php ←tri-gram
0.029877967834sec
%

10万文字ほどのデータだと
%php -f morph.php ←正規表現ベース
8.76749396324sec%
%
%php -f ngram.php ←tri-gram
9.08151698112sec%

あんまりかわらないのでワンライナーな正規表現ベースでやってみる。

こんなかんじの正規表現。

$r = preg_match_all('/[一-龠々〆ヵヶ]+|[ぁ-ん]+|[ァ-ヴ]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+/u', $str, $m);
 

この正規表現で各レコードの本文を割って
出てきたトークンを一つづつハッシュにしてjoinする

$tempToken = array();
foreach ($m as $v) {
    $hashedToken[] = md5($v);
}
$joinedToken = join(' ',$hashedToken);
 

でこれをトークン専用カラムを作成してそこに突っ込む。

ここまでできたら
検索クエリも上の正規表現でトークンにしてそれをmd5にしてから検索。

テストしてみる
全文中から 86deb27a32903da70a7b2348fcf36bc3(あいうえおのmd5) を検索

SELECT id,MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3')
FROM **table
WHERE MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3')
ORDER BY MATCH (test_fulltext) AGAINST ('86deb27a32903da70a7b2348fcf36bc3') ASC

クエリの実行時間 0.0065 秒
 

おーあたったあたった。
しかもこれなら mysqld のft_min_word_lenを4からいじれないっていう件も
強制32文字になるわけだから解決!

ちょいと手間だし、トークンの数 * 32バイト分1レコードのデータが膨れ上がりますが
(まあ全文字md5にしないで、マルチバイトのとこだけ切り出してるわけだから、
そこだけエンコードしてしまえば結構減るかも)
こういう方法で一応できるということで。

っていうか pack() とか使えばもっと短くなるかな。

Leave a Reply