設定が変更できないDBで日本語でfull text searchを実現する

執筆日: 更新日:

nnahitoのサーバをなんとなくレンタルサーバに移動させました。
そしたらDBの設定がいじれなくて、full text searchでn-gramが使えず、記事が一切マッチングしなくなりました。
それを直したお話。

ngramってなに?

文字をn個の塊で考えることです。

例:今日は渋谷に行く

今日
日は
は渋
谷に
に行
行く

こんな感じです。
これはngramのうちの2gram(bi-gram)です。
N=2ですね。

tri-gram(N=3)だと、

今日は
日は渋
は渋谷
渋谷に
谷に行
に行く

ですね。

これを使うと、日本語でもある程度マッチングしますが、それが使えなかったというお話。

検索用のテーブル/カラムを作る

じゃあどうするか。
検索用のカラムを作ってやればいい。

MySQLのデフォルトのfull text searchは半角スペース区切りで文字列を区切り、Indexをリスト化します。
英語だとわかりやすいですよね?

I have an apple

I have an apple

と、このようにスペースでわけます。

しかし、日本語はスペース区切りの文法じゃありません。

私はりんごを持っています

りんご 持っ ます

はい、むずいですよね。
これを解決するのが形態素解析です。

MeCabや、GiNZAなどが有名ですよね?

ただ今回はレンタルサーバ。
Pythonをぶっこむのも一苦労です。

じゃあどうするか。

精度は落ちますが、TinySegmenter PHPを使います。
文字を重み付けしていき、単語に区切るという、すげー発想です。天才じゃねーか?
なので、辞書がなくても動きます。やべーよ。

ということでこれを利用し、文章を形態素解析し、スペース区切りにしてあげます。
そしてそれをfull text searchのindexが貼られたカラムに突っ込み、検索の際にそちらを参照します。

そして検索の際に入力されたテキストも半角スペース区切りにしてSQLにぶっこみます。

検索SQLはこんな感じになります

SELECT *
FROM article_search_index
WHERE MATCH(search_content) AGAINST ('私 りんご' IN NATURAL LANGUAGE MODE);

これでそこそこの精度の日本語検索ができるようになりました。
ソースはこのブログの検索機能です。

以上


[PR] おすすめの本

Nな人

この記事を書いた人

Nな人(えぬなひと)

Laravelが大好きなPHPerで、WEBを作るときはLaravelを技術スタックに絶対推すマン。 PHP、Pythonと、昔はperlを書いていたP言語エンジニア。 最近はNimを書いたりしています。