Kouhei Sutou
kou****@cozmi*****
2013年 4月 21日 (日) 19:17:19 JST
須藤です。 In <42057****@web10*****> "[groonga-dev,01304] utf8_unicode_ciカラムでのLIKE検索時の挙動について" on Sun, 21 Apr 2013 11:57:03 +0900 (JST), <mail_babir****@yahoo*****> wrote: > また、もう一点、前回と同一原因かは不明ですが、utf8_unicode_ci時のLIKE検索において、動作に問題があるようでしたので、ご連絡させて頂きます。 > > 具体的には、utf8_unicode_ci使用時のLIKE検索前方一致において、検索条件に完全一致した場合の結果が含まれないというものです。 こちらでも再現したので確認しました。 ちょっと、直し方を考えないといけないので、回避策を紹介します。 まず、INDEXをFULLTEXT INDEXにして、parserをTokenDelimitNull にします。本当はparserなしにしたいのですが、今はそれはできな いのでTokenDelimitNullで代用しています。 CREATE TABLE `test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `main` varchar(255) NOT NULL COLLATE 'utf8_unicode_ci', PRIMARY KEY (`id`), FULLTEXT INDEX main (`main`) COMMENT 'parser "TokenDelimitNull"' ) ENGINE=mroonga DEFAULT CHARSET=utf8; 検索するときはLIKEではなくMATCH AGAINSTを使うのですが、検索 語の最後に「*」をつけてください。これで、groongaの前方一致検 索機能を使えます。 SELECT * FROM `test` WHERE MATCH(`main`) AGAINST('とらっく*' IN BOOLEAN MODE); 処理を確認したらLIKEのときでもインデックスを使ってましたが、 MATCH AGAINSTでもインデックスを使うので、同じくらい速く動く はずです。 以下、調べた内容のメモです。 MySQLはVARCHAR(N)など、サイズが決まっている文字列のときは文字 列の足りない部分(右側の余っている部分)を埋めるのですが、確 認してみたところ、utf8_unicode_ciの場合はタブ文字(U+0009)で 埋めるようです。 utf8_general_ciの場合はU+0000で埋めるようです。 一方、groongaは可変長文字列として扱い、何かの文字で埋めるよ うなことはしていません。つまり、groongaのインデックスには 「とらっく」と「とらっくばっく」が入っています。 MySQLは「とらっく\t\t\t\t\t...」という文字列より大きい文字列 というリクエストをmroongaに渡してきます。utf8_general_ciの場 合は「とらっく\0\0\0\0...」を渡してきます。 groongaは「とらっく\0\0\0\0...」を指定された場合は「とらっく」 を大きい値をみなしますが、「とらっく\t\t\t\t...」を指定され た場合は「とらっく」を小さい値とみなしてヒットさせません。 なので、utf8_general_ciのときはヒットしてutf8_unicode_ciのと きはヒットしません。 うーん、どうするのがいいのかしら。右側にある field->charset()->min_sort_charを全部\0に置き換えちゃうのがよ い気がするけど。。。 -- 須藤 功平 <kou****@clear*****> 株式会社クリアコード <http://www.clear-code.com/> (03-6231-7270) groongaサポート: http://groonga.org/ja/support/ パッチ採用はじめました: http://www.clear-code.com/recruitment/ コミットへのコメントサービスはじめました: http://www.clear-code.com/services/commit-comment.html