InnoDB FULLTEXT Search の ngram_token_size
ngram_token_size パラメータは InnoDB FTS の ngram パーサーの設定です。ngram_token_size に指定した文字数ごとに文章をトークナイズします。
疑問
- ngram_token_size をインデックス作成後から変更すると、どうなるのか?
- あり得るパターン
試してみます
mysql> SET GLOBAL ngram_token_size=3; ERROR 1238 (HY000): Variable 'ngram_token_size' is a read only variable
おっと、、、ngram_token_size はオンラインで変更できなかった、、、 この時点で、パターン2臭がする、、、
まず、token_size=2 で インデックスを作ります。
mysql> SHOW GLOBAL VARIABLES LIKE 'ngram_token%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | ngram_token_size | 2 | +------------------+-------+ 1 row in set (0.00 sec) mysql> INSERT INTO fts.fts_check (col1) VALUES('にぐらむ'); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM information_schema.INNODB_FT_INDEX_CACHE; +--------+--------------+-------------+-----------+--------+----------+ | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION | +--------+--------------+-------------+-----------+--------+----------+ | ぐら | 6 | 6 | 1 | 6 | 3 | | にぐ | 6 | 6 | 1 | 6 | 0 | | らむ | 6 | 6 | 1 | 6 | 6 | +--------+--------------+-------------+-----------+--------+----------+ 3 rows in set (0.00 sec)
ngram_toke_size=2、2文字区切りで、トークナイズされていることが確認できました。 次に、ngram_toke_size=3 にして、データを追加します。
mysql> SHOW GLOBAL VARIABLES LIKE 'ngram_token%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | ngram_token_size | 3 | +------------------+-------+ 1 row in set (0.00 sec) mysql> INSERT INTO fts.fts_check (col1) VALUES('トリグラム'); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM information_schema.INNODB_FT_INDEX_TABLE; +--------+--------------+-------------+-----------+--------+----------+ | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION | +--------+--------------+-------------+-----------+--------+----------+ | ぐら | 6 | 6 | 1 | 6 | 3 | | にぐ | 6 | 6 | 1 | 6 | 0 | | らむ | 6 | 6 | 1 | 6 | 6 | +--------+--------------+-------------+-----------+--------+----------+ 3 rows in set (0.00 sec) mysql> SELECT * FROM information_schema.INNODB_FT_INDEX_CACHE; +-----------+--------------+-------------+-----------+--------+----------+ | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION | +-----------+--------------+-------------+-----------+--------+----------+ | グラム | 8 | 8 | 1 | 8 | 6 | | トリグ | 8 | 8 | 1 | 8 | 0 | | リグラ | 8 | 8 | 1 | 8 | 3 | +-----------+--------------+-------------+-----------+--------+----------+ 3 rows in set (0.00 sec)
パターン2 でした!新しく登録したレコードは設定変更の影響を受けて3文字区切りでトークナイズされてる。 1つのインデックスに2文字区切りと、3文字区切りでトークナイズされた結果が混ざってしまっています。
念の為、検索して、確認してみます。
mysql> SHOW GLOBAL VARIABLES LIKE 'ngram_token%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | ngram_token_size | 3 | +------------------+-------+ 1 row in set (0.00 sec) mysql> SELECT * FROM fts_check WHERE MATCH(col1) AGAINST (+'にぐ' IN BOOLEAN MODE); +----+--------------+ | id | col1 | +----+--------------+ | 1 | にぐらむ | +----+--------------+ 1 row in set (0.00 sec) -- ngram_token_size = 3 なので、「にぐら」でインデックスから検索する。 -- インデックスには「にぐ」しかないのでヒットしない。 mysql> SELECT * FROM fts_check WHERE MATCH(col1) AGAINST (+'にぐら' IN BOOLEAN MODE); Empty set (0.01 sec) -- インデックスに「トリ」はないのでヒットしない mysql> SELECT * FROM fts_check WHERE MATCH(col1) AGAINST (+'トリ' IN BOOLEAN MODE); Empty set (0.00 sec) mysql> SELECT * FROM fts_check WHERE MATCH(col1) AGAINST (+'トリグ' IN BOOLEAN MODE); +----+-----------------+ | id | col1 | +----+-----------------+ | 4 | トリグラム | +----+-----------------+ 1 row in set (0.00 sec)
まとめ
- ngram_token_size を変更したら、インデックスを再作成しないと、既存のインデックスに反映されない
mysql> OPTIMIZE TABLE fts_check; +---------------+----------+----------+-------------------------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +---------------+----------+----------+-------------------------------------------------------------------+ | fts.fts_check | optimize | note | Table does not support optimize, doing recreate + analyze instead | | fts.fts_check | optimize | status | OK | +---------------+----------+----------+-------------------------------------------------------------------+ 2 rows in set (0.05 sec)
- そして、スキーマやテーブルごとにngram_token_sizeを変更することはできない