2014年12月12日金曜日

Mroongaの全文検索が上手くいかない気がするときの初動メモ

この記事は Groonga Advent Calendar 2014 の12日目の記事です。

最初は「Mroonga with MySQL Fabric(仮)」というタイトルを考えていたんですが、MySQL FabricはフツーのMySQLサーバーの上でマスター昇格とかよしなにやってくれるためのミドル(?)ウェアなので、Mroongaも動いて当たり前だと思ってやめました。

じゃあ別のMySQLのHA実装のXtraDB Clusterでもやろうかなと思いましたが、よく考えたらそれはもう1年半前にやっていて ( mroongaをXtraDB Clusterで冗長化できそうなメモ ) 当時はまだ"m"が小文字だったんだなーとか感慨深いですね。
PXCも5.6になりましたしwsrepもバージョン上がってますが、今でもできるのかどうかは知りません。誰か試してください。

MySQL Cluster with Mroongaは仕組み上不可能だし (ラッパーモード使っても、SQLノード上に転置索引が作成されるのでダメ) もうHAやめて、フツーに普段やっていることをメモしておこうと思います。

長かったな前置き。


基本的にMySQLしか触ったことなかった人がMroongaで全文検索…なのを想定しています。そう、俺だ。
さて、何はともあれテーブルの定義を確認したりします。


mysql56> use d1
Database changed

mysql56> CREATE TABLE t1 (num serial, val varchar(32), FULLTEXT KEY(val)) Engine= Mroonga Comment= 'Engine "InnoDB"';
Query OK, 0 rows affected (0.06 sec)

mysql56> SELECT mroonga_command('table_list')\G
*************************** 1. row ***************************
mroonga_command('table_list'): [[["id","UInt32"],["name","ShortText"],["path","ShortText"],["flags","ShortText"],["domain","ShortText"],["range","ShortText"],["default_tokenizer","ShortText"],["normalizer","ShortText"]],[259,"t1","d1.mrn.0000103","TABLE_HASH_KEY|PERSISTENT","ShortText",null,null,null],[260,"t1-val","d1.mrn.0000104","TABLE_PAT_KEY|PERSISTENT","ShortText",null,"TokenBigram","NormalizerMySQLGeneralCI"]]
1 row in set (0.00 sec)

mysql56>
mysql56> SELECT mroonga_command('table_list --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('table_list --output_type tsv'): "id"   "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigram"
"NormalizerMySQLGeneralCI"
1 row in set (0.02 sec)

特に何もこだわりがないときは--output_type tsvを指定しておくと、改行が多くなって見やすいのでわたしは好きです。

groongaコマンドラインクライアントから叩くときは、余計なものが何もついていない"データベース名".mrnファイルを指定します。


$ /usr/groonga/4.0.6/bin/groonga d1.mrn
> table_list --output_type tsv
0       1418374830.69561        0.00125479698181152
"id"    "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigram"
"NormalizerMySQLGeneralCI"
END

何が書いてあるのか詳しくは判りませんが、転置索引はt1-val("テーブル名"-"インデックス名")というオブジェクトに入っているようです。
トークナイザーはTokenBigram, ノーマライザーはNormalizerMySQLGeneralCIですね。トークナイザーやノーマライザーをTypoするとここが想定しているのと違う値になったりしますね_| ̄|○


mysql56> SELECT * FROM t1;
+-----+----------+
| num | val      |
+-----+----------+
|   1 | yoku0825 |
|   2 | yoku0826 |
+-----+----------+
2 rows in set (0.00 sec)

mysql56> SELECT mroonga_command('select t1-val --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('select t1-val --output_type tsv'): 3
[       "_id"   "UInt32"        ]       [       "_key"  "ShortText"     ]       [       "index" "t1"    ]
2       "0825"  1
3       "0826"  1
1       "YOKU"  4
1 row in set (0.02 sec)

実際にトークナイズされた結果が見られます。本番でこれをやると結構大変なので、CREATE TABLE .. LIKE, INSERT INTO .. SELECTでズレてる気がする行だけを抽出して読みます。


mysql56> ALTER TABLE t1 DROP KEY val;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql56> ALTER TABLE t1 ADD FULLTEXT KEY (val) Comment 'parser "TokenBigramIgnoreBlankSplitSymbolAlphaDigit"';
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql56> SELECT mroonga_command('table_list --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('table_list --output_type tsv'): "id"   "UInt32"
"name"  "ShortText"
"path"  "ShortText"
"flags" "ShortText"
"domain"        "ShortText"
"range" "ShortText"
"default_tokenizer"     "ShortText"
"normalizer"    "ShortText"
259
"t1"
"d1.mrn.0000103"
"TABLE_HASH_KEY|PERSISTENT"
"ShortText"



260
"t1-val"
"d1.mrn.0000104"
"TABLE_PAT_KEY|PERSISTENT"
"ShortText"

"TokenBigramIgnoreBlankSplitSymbolAlphaDigit"
"NormalizerMySQLGeneralCI"
1 row in set (0.02 sec)

mysql56> SELECT mroonga_command('select t1-val --limit -1 --output_type tsv')\G
*************************** 1. row ***************************
mroonga_command('select t1-val --limit -1 --output_type tsv'): 10
[       "_id"   "UInt32"        ]       [       "_key"  "ShortText"     ]       [       "index" "t1"    ]
5       "08"    8
7       "25"    1
9       "26"    1
8       "5"     1
10      "6"     1
6       "82"    9
3       "KU"    6
2       "OK"    5
4       "U0"    7
1       "YO"    4
1 row in set (0.02 sec)

たとえばトークナイザーを変えるとどうなるんだとかいうのはこのように調べています。(Groongaの)selectコマンドは暗黙に--limit 10を押し込んでくれるので、トークンが10個以上に分かれる(たぶん、フツーは分かれる、だろう)場合は--limit -1で無制限に出力させられます。

こんな感じで調べて、なんかどうも全角の記号より後ろに詰められた文字がちゃんとトークナイズされてなくね? とかいうのに気付いたり気付かなかったりします。
http://sourceforge.jp/projects/groonga/lists/archive/dev/2014-February/002110.html


ちなみにTritonn時代にもsennaコマンドラインクライアント(たぶんgroongaコマンドラインクライアントと同じような機能を持っていたんだろうけれど)があったんですが、こっちはコマンドのドキュメントがどこにも存在しなかったので挫折しました。。(TritonnからMroongaへの移行の時に、同じようなのが見られたら少し便利だっただろうなぁ、と思いつつ)

とはいえ、「検索結果がおかしい」ことに気付くのって難しいですよね。。

0 件のコメント :

コメントを投稿