タグ検索で大文字・小文字を区別する仕様とその実装方法について(MySQL編)
TagClickの加藤です。
Livedoor Knowledgeでこんな質問を見つけました。
「livedoor clip」にてアルファベット(大文字・小文字)のタグの表記について
実はTagClickにもスタート当時同様の制約がありました。その後修正して、今は「登録および表示は大文字、小文字を区別」、「検索時は大文字、小文字を区別しない」というタグの仕様になっています。分かりやすくいうと、
- タグをつけるときは大文字・小文字をそのまま保存
- タグクラウドなどでは、例えばGoogleとgoogleは別々に表示
- タグ検索時はGoogleでもgoogleでも同じ検索結果になる
ということです。多分ライブドアさんでもDBにMySQLを使っていると思うので、参考までに当社の藪崎がおこなった解決策を紹介します(ここからは技術的なハナシ)。
MySQLはデフォルトでは大文字・小文字を区別しないため、この問題を解決するためには拡張機能を利用する必要があります。MySQLリファレンスマニュアルの該当ページでは以下のように記述されています。
すべての文字列比較は、デフォルトでは大文字と小文字を区別せず、現在のキャラクタセット(デフォルトでは ISO-8859-1 Latin1)で決められたソート順で行われる。これを変更するには、BINARY 属性を指定してカラムを宣言するか、BINARY キャストを使用して、MySQL サーバホストで使用される ASCII の順序に従って比較が行われるようにする必要がある。
つまり、テーブルを作成・更新する際に該当カラムにBINARY属性をつけるか、検索時にBINARYキャストを使用しないと大文字・小文字は区別されないわけです。で、どちらの方法で解決するかというハナシになるわけですが、それぞれ一長一短があります。
まず、該当カラムにBINARY属性をつけた場合、登録・表示に関しては何も考えなくても区別してくれるのでラクなのですが、検索時には大文字・小文字の違いですべての組み合わせを確認しなければなりません。例えば、タグ「Web」で検索して期待したタグを得るためには以下のようなSQLになってしまいます。
SELECT * FROM tags WHERE name IN ('WEB', 'WEb', WeB', .....);
逆に該当カラムにBINARY属性をつけない場合は検索文字はどの組み合わせでも良いのでラクなのですが、同時にユニーク制約もつけられなくなるので(WebとWEBを同一視してしまうため)、テーブル内で大文字・小文字を区別してタグを一意にするには登録前にあらかじめ以下のようなSQLでタグの存在を確認してから登録する必要がでてきてしまいます。
SELECT * FROM tags WHERE BINARY name = 'Web';
結局、どちらの方法でもアプリケーション側でカバーするしか方法がないのですが、TagClickでは検索の方が圧倒的に回数が多いので後者の方法を取っています。この他にも、タグと関連するテーブルに検索用の文字列カラムをつけてフルテキスト検索で処理する方法とかもあるみたいですが、ウチではまだ試せていません。
TagClickでも、「トップページのタグクラウドではGoogleとgoogleは一緒にした方が良いんじゃないの?」とか、「漢字のタグって順番分かりづらいよね?」など、まだまだ技術的な課題は多いので、今後も色々と調査していきたいと思っています。
