一つのカラムに貼られた複数のFULLTEXT INDEXを使い分ける

2015/7/26

Mroongaでお手軽全文検索して遊んでいたんですが、前方一致を使う場合は

Qiita: mroongaでgroongaの前方一致検索を使うには

にあるように、パーサーを無効にしないと期待した結果が得られません。

一つのカラムに対して、普通に全文検索する場合と前方一致検索を使い分けたい場合には、上記記事のように2つカラム用意してそれぞれにパーサーを使ったFULLTEXT INDEXと、無効にしたFULLTEXT INDEXを貼らなきゃいけないのでしょうか。
ちょっと無駄な感じがしましてどうにかできないかな~と。

そこで思いついたのが、USE INDEXとかで明示的にインデックスを指定してやったらどうなるのでしょうか。
そんでリファレンスを見てみると・・・

MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.2.9.3 インデックスヒントの構文

「自然言語モードの検索の場合、インデックスヒントは暗黙のうちに無視されます。」
を読んで、ダメか~と思ったのですが、
「ブールモードの検索の場合、FOR ORDER BY または FOR GROUP BY を含むインデックスヒントは暗黙のうちに無視されます。FOR JOIN を含むインデックスヒント、または FOR 修飾子を含まないインデックスヒントは受け付けられます。」
ということらしいのでIN BOOLEAN MODEであれば、FOR {ORDER|GROUP} BYを除き、使えるっぽいですね。

ということで試してみましょう。

サンプルとして使うスキーマとデータは以下の通り。

CREATE TABLE test (
  id int(11) NOT NULL AUTO_INCREMENT,
  content varchar(255) NOT NULL COLLATE 'utf8_unicode_ci',
  PRIMARY KEY (id),
  FULLTEXT INDEX idx_content (content),
  FULLTEXT INDEX idx_content_off (content) COMMENT 'parser "off"'
) ENGINE=mroonga COMMENT = 'engine "InnoDB"' DEFAULT CHARSET=utf8;
INSERT INTO test (content) VALUES ('とらっく');
INSERT INTO test (content) VALUES ('とらっくばっく');
INSERT INTO test (content) VALUES ('東京都');
INSERT INTO test (content) VALUES ('京都');

まずはインデックスを指定せず前方一致検索をしてみます。

SELECT * FROM `test` WHERE MATCH(content) AGAINST('とらっく*' IN BOOLEAN MODE)

検索結果は空でした。EXPLAINしてみると、使用されたのはidx_contentが使われていたので、正しい結果です。

お次はUSE INDEXでパーサを無効にしたidx_content_offを指定してみます。

SELECT * FROM `test` USE INDEX (idx_content_off) WHERE MATCH(content) AGAINST('とらっく*' IN BOOLEAN MODE)

すると、以下のような結果が得られました。
idx_content_offが使用され、意図した前方一致検索が行われているようです。

|2|とらっくばっく
|1|とらっく

ということで、USE INDEXを使うことで、異なるパーサを用いたFULLTEXT INDEXを使い分けすることができますね。