MySQL :: MySQL 5.7 Reference Manual :: 12.9.9 InnoDB MeCab Full-Text Parser Plugin の内容のおさらい。
まず、基本的なライブラリーと辞書は(この記事を書いている時点では).tar.gzバイナリーに同梱されているっぽいのでそちらを使う。Oracle公式のyumリポジトリーからインストールできるrpmには含まれていないように見えるので、その場合は別途突っ込まないといけないはずだけど、libpluginmecab.soが何かにダイナミックリンクしているわけではないので、辞書だけ取ってきてmecabrcに設定すればいけるような気がする。詳しく調べてない。
この環境はバイナリーの.tar.gzを取ってきて、/usr/local/mysqlに展開したとして、
plugin_dirにあたるlib/pluginにlibpluginmecab.soが、その他InnoDB MeCab Pluginに必要な辞書(dic)とか設定ファイル(etc)をおさめたディレクトリがlib/mecabにある。
続いてmy.cnfをゴニョる。
mecab-rc-fileはlib/mecab/etc/mecabrcのパスを絶対パスで[mysqld]セクションに記述する。loose-接頭辞をつけておかないとMySQLが起動しなくなるので注意(INSTALL PLUGIN前にこのオプションを渡そうとすると、"unknown option"って言われてmysqldが起動してくれない)
参考: MySQL の unknown option エラーはオプションに loose- プレフィックスをつけると回避できる - かみぽわーる
innodb_ft_min_token_sizeはこのサイズより小さい文字列はトークンにしないというオプションだが、暗黙のデフォルトは3。英語で"a"とか"to"とかそういう頻出単語をトークナイズしないようにするためと書いてある。CJKでは1にセットしてね、とも。
my.cnfの次はmecabrc(↑のmy.cnfに記述したパスにあるもの)をゴニョる。
dicdirに、使いたい辞書の入っているディレクトリを指定する。
5.7.6現在、euc-jp, sjis, utf-8の3つが入ってる。5.7.7のリリースノート を見ると eucjpms, cp932, utf8mb4に対応したよ! と書いてあって、マニュアルのページには同じ辞書を使うよ、と書いてある。
この状態で起動してやると、
まだINSTALL PLUGINしてないので、unknown variableとして扱われる。
認識したぽい。
こんな感じのWikipediaのデータを食わせたテーブルに
なんかダイイングメッセージみたいに不明なエラー吐いてるけど(Mroongaと比較した感じでは"too long sentence"エラーのはず)取り敢えず無視して、
引けてるっぽい。
バッファプールに載ってて単一条件ならまあまあ動くんだけど
スコア以外のところでソートするとやっぱり死ねるねぇ。。
【2015/03/10 18:57】
Ngramの方も書きました => 日々の覚書: MySQL 5.7.6のInnoDB日本語全文検索 ngram
まず、基本的なライブラリーと辞書は(この記事を書いている時点では).tar.gzバイナリーに同梱されているっぽいのでそちらを使う。Oracle公式のyumリポジトリーからインストールできるrpmには含まれていないように見えるので、その場合は別途突っ込まないといけないはずだけど、libpluginmecab.soが何かにダイナミックリンクしているわけではないので、辞書だけ取ってきてmecabrcに設定すればいけるような気がする。詳しく調べてない。
この環境はバイナリーの.tar.gzを取ってきて、/usr/local/mysqlに展開したとして、
$ ll /usr/local/mysql/lib/plugin/*mecab*
-rwxr-xr-x 1 root root 3988451 Feb 10 20:28 /usr/local/mysql/lib/plugin/libpluginmecab.so
$ ll -R /usr/local/mysql/lib/mecab
/usr/local/mysql/lib/mecab/:
total 8
drwxr-xr-x 5 root root 4096 Feb 17 10:54 dic
drwxr-xr-x 2 root root 4096 Feb 23 21:59 etc
..
plugin_dirにあたるlib/pluginにlibpluginmecab.soが、その他InnoDB MeCab Pluginに必要な辞書(dic)とか設定ファイル(etc)をおさめたディレクトリがlib/mecabにある。
続いてmy.cnfをゴニョる。
$ vim /etc/my.cnf
..
[mysqld]
loose-mecab-rc-file= /usr/local/mysql/lib/mecab/etc/mecabrc
innodb_ft_min_token_size= 1
..
mecab-rc-fileはlib/mecab/etc/mecabrcのパスを絶対パスで[mysqld]セクションに記述する。loose-接頭辞をつけておかないとMySQLが起動しなくなるので注意(INSTALL PLUGIN前にこのオプションを渡そうとすると、"unknown option"って言われてmysqldが起動してくれない)
参考: MySQL の unknown option エラーはオプションに loose- プレフィックスをつけると回避できる - かみぽわーる
my.cnfの次はmecabrc(↑のmy.cnfに記述したパスにあるもの)をゴニョる。
$ vim /usr/local/mysql/lib/mecab/etc/mecabrc
..
dicdir = /usr/local/mysql/lib/mecab/dic/ipadic_utf-8
dicdirに、使いたい辞書の入っているディレクトリを指定する。
# ll lib/mecab/dic/
total 12
drwxr-xr-x 2 root root 4096 Feb 17 10:54 ipadic_euc-jp
drwxr-xr-x 2 root root 4096 Feb 17 10:54 ipadic_sjis
drwxr-xr-x 2 root root 4096 Feb 17 10:54 ipadic_utf-8
5.7.6現在、euc-jp, sjis, utf-8の3つが入ってる。5.7.7のリリースノート を見ると eucjpms, cp932, utf8mb4に対応したよ! と書いてあって、マニュアルのページには同じ辞書を使うよ、と書いてある。
この状態で起動してやると、
$ bin/mysqld_safe &
$ less data/error.log
..
2015-03-04T02:30:12.628925Z 0 [Warning] unknown variable 'loose-mecab-rc-file=/usr/local/mysql/lib/mecab/etc/mecabrc'
..
まだINSTALL PLUGINしてないので、unknown variableとして扱われる。
mysql> INSTALL PLUGIN mecab SONAME 'libpluginmecab.so';
Query OK, 0 rows affected (0.20 sec)
$ tail data/error.log
2015-03-04T03:21:46.236551Z 2 [Note] Mecab: Trying createModel(--rcfile=/usr/local/mysql/lib/mecab/etc/mecabrc)
2015-03-04T03:21:46.436600Z 2 [Note] Mecab: Loaded dictionary charset is utf-8
認識したぽい。
mysql> SHOW CREATE TABLE articles;
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| articles | CREATE TABLE `articles` (
`seq` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` text,
`content` longtext,
`timestamp` datetime DEFAULT NULL,
UNIQUE KEY `seq` (`seq`),
KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB AUTO_INCREMENT=1914065 DEFAULT CHARSET=utf8 |
+----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
こんな感じのWikipediaのデータを食わせたテーブルに
mysql> ALTER TABLE articles ADD FULLTEXT KEY (title, content);
Query OK, 0 rows affected (1 hour 2 min 12.62 sec)
Records: 0 Duplicates: 0 Warnings: 0
$ tail data/error.log
2015-03-04T03:39:02.484153Z 0 [ERROR] Mecab:
2015-03-04T03:40:06.299126Z 0 [ERROR] Mecab:
2015-03-04T03:45:13.146195Z 0 [ERROR] Mecab:
2015-03-04T03:56:10.793337Z 0 [ERROR] Mecab:
2015-03-04T03:56:21.149414Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.385256Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.421553Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.470875Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.600808Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.632828Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.941143Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.969369Z 0 [ERROR] Mecab:
2015-03-04T03:59:34.986076Z 0 [ERROR] Mecab:
2015-03-04T03:59:35.056543Z 0 [ERROR] Mecab:
2015-03-04T03:59:35.352131Z 0 [ERROR] Mecab:
2015-03-04T03:59:36.754206Z 0 [ERROR] Mecab:
なんかダイイングメッセージみたいに不明なエラー吐いてるけど(Mroongaと比較した感じでは"too long sentence"エラーのはず)取り敢えず無視して、
mysql> SELECT COUNT(*) FROM articles WHERE match(title, content) against('データベース');
+----------+
| COUNT(*) |
+----------+
| 3013 |
+----------+
1 row in set (0.01 sec)
mysql> explain SELECT COUNT(*) FROM articles WHERE match(title, content) against ('データベース');
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------+
1 row in set, 1 warning (0.01 sec)
mysql> SHOW WARNINGS;
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select count(0) AS `COUNT(*)` from `wikipedia`.`articles` where (match `wikipedia`.`articles`.`title`,`wikipedia`.`articles`.`content` against ('データベース')) |
+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)
引けてるっぽい。
mysql> explain SELECT * FROM articles WHERE match(title, content) against ('データベース') LIMIT 10;
+----+-------------+----------+------------+----------+---------------+-------+---------+-------+------+----------+-------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+----------+---------------+-------+---------+-------+------+----------+-------------------------------------------+
| 1 | SIMPLE | articles | NULL | fulltext | title | title | 0 | const | 1 | 100.00 | Using where; Ft_hints: sorted, limit = 10 |
+----+-------------+----------+------------+----------+---------------+-------+---------+-------+------+----------+-------------------------------------------+
1 row in set, 1 warning (0.02 sec)
mysql> SELECT * FROM articles WHERE match(title, content) against ('データベース') LIMIT 10;
..
10 rows in set (0.01 sec)
バッファプールに載ってて単一条件ならまあまあ動くんだけど
mysql> SELECT * FROM articles WHERE match(title, content) against ('データベース') ORDER BY timestamp DESC LIMIT 10;
..
10 rows in set (0.62 sec)
スコア以外のところでソートするとやっぱり死ねるねぇ。。
【2015/03/10 18:57】
Ngramの方も書きました => 日々の覚書: MySQL 5.7.6のInnoDB日本語全文検索 ngram