インデックス作成時に指定可能なフラグにSPLIT系を追加

SPLIT_ALPHA、SPLIT_DIGIT、SPLIT_SYMBOLという3つのSennaインデックス作成用フラグをUSING句で使えるようにしました。

これらのフラグはSenna本体では以前からサポートしていたのですが、これまではMySQLDDL経由で指定することができませんでした。今回の対応によりMySQLからも指定可能となります。

この変更はsourceforgeのレポジトリに既にcommitしています(rev16)。特に問題がなければtritonn-1.0.5にて正式に導入するつもりです。

これを使うと何が便利になるの?

以下のようなINSERT文でNGRAMで作ったインデックスに1レコード追加したとします。

insert into t1 values ("FedoraCore500の技");

このときSPLIT系フラグが指定されていないと、以下のSELECT文では上記レコードをヒットさせることができません。

SELECT * FROM t1 WHERE MATCH(c1) AGAINST("00");
SELECT * FROM t1 WHERE MATCH(c1) AGAINST("Core");

この検索漏れは、NO NORMALIZEを指定することで回避できますが、NO NORMALIZEを使うと今度は以下のSELECT文でレコードをヒットさせることができなくなります。

SELECT * FROM t1 WHERE MATCH(c1) AGAINST("500");

これはUnicode正規化の機能をOFFにしてしまったためです。

こんな時、SPLIT系のフラグを指定してインデックスを作成しておくと上記全てのパタンでレコードをヒットさせることができます。

開発経緯

この対応を行うこととなった経緯についてはMLのログを参照してください。

実行例

以下、実行例です。

[test] > create table t1 (c1 text, fulltext index ft
    -> using ngram, split_alpha, split_digit, split_symbol (c1))
    -> default charset utf8 engine = myisam;
Query OK, 0 rows affected (0.01 sec)

[test] > show senna status\G
*************************** 1. row ***************************
                  Table: t1
               Key_name: ft
            Column_name: c1
               Encoding: utf8
             Index_type: NGRAM
           Sectionalize: OFF
              Normalize: ON
            Split_alpha: ON
            Split_digit: ON
           Split_symbol: ON
     Initial_n_segments: 512
        Senna_keys_size: 0
   Senna_keys_file_size: 4268032
     Senna_lexicon_size: 0
Senna_lexicon_file_size: 4268032
     Senna_inv_seg_size: 167936
   Senna_inv_chunk_size: 135168
1 row in set (0.00 sec)

[test] > insert into t1 values ("FedoraCore500の技");
Query OK, 1 row affected (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("500");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("00");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("Core");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("Fedo");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("50");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)

[test] > SELECT * FROM t1 WHERE MATCH(c1) AGAINST("500");
+---------------------+
| c1                  |
+---------------------+
| FedoraCore500の技 |
+---------------------+
1 row in set (0.00 sec)