WEBサービス創造記

WEBサービスを作ったり保守したりしてる人のメモブログです。

MySQLでgroongaを利用して高速に日本語の全文検索を行う

      2012/12/11

MySQLでの全文検索

全文検索とは複数の検索対象から特定のキーワードを含むテキストを(インデックスを使用して)検索することです。
残念ながら、MySQLでは日本語環境で全文検索を行うための充分な機能が備えられていません。

どういうことかというと、一般的にMySQLでの全文検索では、”SELECT カラム名 FROM テーブル名 WHERE MATCH(カラム名) AGAINST(‘キーワード’)”のようなMATCH/AGAINSTを利用します(検索対象のカラムにはFULLTEXTインデクスが指定されている必要もあります)。
しかし、以下のような理由から、MySQLでは日本語ではこの構文が動作しません。

MySQLのFULLTEXTインデックスのキーワード抽出を行うパーサが「半角スペース(もしくは.,)で区切られているものをキーワードとして認識する」という実装になっている。

これは、単語がスペースで区切られる英語の文法では問題ありませんが、単語がスペースで区切られない日本語ではFULLTEXTインデックスは意味をなさないことになります。

FULLTEXTインデックスによるもの以外で日本語を検索する方法としてはLike演算子の利用がありますが、Like演算子の大きな問題点は、インデックスを一切使用することができなくなってしまうため、テーブルのフルスキャンが発生してしまうことです。

小規模なサービスだとLike検索だとそれほど気を使わなくてもいいかもしれませんが、大規模なサービスだとLike検索のオーバヘッドは致命的といえます。
そこで、日本語でも全文検索を利用できるように設定します。

もっと詳しく知りたい方は、以下のURLをご覧いただければもっとわかりやすく解説されています。
http://qwik.jp/tritonn/about.html

groongaのインストール

MySQLで日本語の全文検索に対応する方法にはいくつか方法があるようです。
ここでは“Senna”という全文検索エンジンを利用します。
Sennaの後継である『groonga』(ぐるんが)を利用してみます。

ただし、groongaはどうやら32ビットOSには対応していないようです。

既存MySQLモジュールの削除

まずは、既存のMySQLモジュールを削除しておきます。

# yum -y remove mysql*

または、

# yum -y remove MySQL*

必要があれば、古いデータベースも削除しておく。

# rm /var/lib/mysql/*

groongaのリポジトリを追加

続いてリポジトリを追加。

# rpm -ivh http://packages.groonga.org/centos/groonga-repository-1.0.0-0.noarch.rpm
# yum -y update

MySQLのインストール

# yum install -y MySQL-server

groongaのインストール

形態素解析エンジンであるMeCabとMeCabの辞書もインストールします。

# yum install -y groonga groonga-devel groonga-tokenizer-mecab mecab-ipadic mecab-jumandic

MySQLを起動後、mysql-groonga をインストール

# /etc/init.d/mysql start
# yum -y install mysql-groonga
# /etc/init.d/mysql restart

MySQLでgroongaを使用する

ストレージエンジンとしてgroongaが利用出来ることを確認。

# /etc/init.d/mysql start
# mysql -uroot

mysql> SHOW ENGINES \G
~(略)~
*************************** 7. row ***************************
      Engine: groonga
     Support: YES
     Comment: Fulltext search, column base
Transactions: NO
          XA: NO
  Savepoints: NO
~(略)~

簡単な動作確認。

groongaの動作確認用のDBとテーブルを作成
mysql> CREATE DATABASE groongatest;
mysql> USE groongatest;
mysql> CREATE TABLE `t1` (
    `c1` int(10) unsigned NOT NULL,
    `c2` varchar(255),
    `c3` text,
    fulltext index(c2), fulltext index(c3),
    PRIMARY KEY (`c1`)
) ENGINE=groonga;

mysql> insert into t1 values(1, "全文検索エンジンの動作確認について","あいうえお");
mysql> insert into t1 values(2, "かきくけこ","全文検索エンジンgroongaの動作確認中です。");
mysql> insert into t1 values(3, "dummy", "dummy");
mysql> select * from t1;
+----+-----------------------------------------------------+------------------------------------------------------------+
| c1 | c2                                                  | c3                                                         |
+----+-----------------------------------------------------+------------------------------------------------------------+
|  1 | 全文検索エンジンの動作確認について                  | あいうえお                                                 |
|  2 | かきくけこ                                          | 全文検索エンジンgroongaの動作確認中です。                  |
|  3 | dummy                                               | dummy                                                      |
+----+-----------------------------------------------------+------------------------------------------------------------+
3 rows in set (0.00 sec)

mysql> select * from t1 where match(c2) against("全文検索");
+----+-----------------------------------------------------+-----------------+
| c1 | c2                                                  | c3              |
+----+-----------------------------------------------------+-----------------+
|  1 | 全文検索エンジンの動作確認について                  | あいうえお      |
+----+-----------------------------------------------------+-----------------+
1 row in set (0.00 sec)
  • ストレージエンジンgroongaはオートインクリメントに対応していない?

 - MySQL , , ,