Movable Typeのタグの「あいまい検索」について
Movable Type 5.0xのタグの「あいまい検索」について、具体的にヒットする検索範囲を調査しましたので紹介します。
1.基本
タグのあいまい検索は、ブログ記事一覧・ウェブページ一覧・アイテム一覧など、タグづけができるオブジェクトについて、フィルタリングする際の項目として選択できます。
本題のあいまい検索でヒットする範囲ですが、、「タグに含まれる半角記号を無視して検索する」という動作になります。
例えばブログ記事Aに「a-b-c」、ブログ記事Bに「a:b:c」というタグがつけられた状態で「abc」や「a-b-c」という文字列でフィルタリングすれば、検索文字列から記号を除去した「abc」という文字列で検索し、さらに検索されるタグについても、それぞれ記号を除去した「abc」として扱い、結果的に両方の記事がヒットします。
半角英文字の大文字・小文字もあいまい検索の対象になります。
2.あいまい検索の仕組み
「a-b-c」「a:b:c」などを「abc」という文字列に変換することを、ここでは「正規化」と呼ぶことにします。実はタグを作成したときに、この正規化されたデータも同時にデータベースに登録されています。下はphpMyAdminでmt_tagテーブルを表示したものです。
tag_idが「4」「6」「8」「10」「12」などのタグはすべて小文字で設定されているのが分かると思いますが、ここに正規化されたタグが入っています。このデータは管理画面から入力したデータではなく、tag_idが「5」「7」「9」「11」「13」をもとに正規化したものです。
そして、tag_idが「5」「7」「9」「11」「13」のtag_n8d_idというフィールドには、正規化されたタグのIDが設定されています。この状態で例えば「AJAX」というタグを追加すれば、すでに正規化されたタグは登録されているので、追加したタグのtag_n8d_idに「4」が設定されます。
このデータ構造によってあいまい検索を実現しています。例は英文字だけですが、日本語が混在していても正規化されます。
ちなみに、タグを正規化するメソッドはMT::Tag::normalizeです。
sub normalize {
my $tag = shift;
my ($str) = @_;
if (!@_ && !(ref $tag)) {
$str = $tag;
} elsif (!$str && (ref $tag)) {
$str = $tag->name;
}
my $private = $str =~ m/^@/;
$str =~ s/[@!`\\<>\*&#\/~\?'"\.\,=\(\)\${}\[\];:\ \+\-\r\n]+//gs;
$str = lc $str;
$str = '@' . $str if $private;
$str;
}
あいまい検索を使ってフィルタリングする処理は、MT::CMS::Entry::listで行っています。n8d_idを利用しているのが分かります。
sub list {
my $app = shift;
…中略…
if ( $filter_col && $filter_val ) {
if ( !exists( $terms{$filter_col} ) ) {
…中略…
elsif (( $filter_col eq 'normalizedtag' )
|| ( $filter_col eq 'exacttag' ) )
{
my $normalize = ( $filter_col eq 'normalizedtag' );
require MT::Tag;
require MT::ObjectTag;
my $tag_delim = chr( $app->user->entry_prefs->{tag_delim} );
my @filter_vals = MT::Tag->split( $tag_delim, $filter_val );
my @filter_tags = @filter_vals;
if ($normalize) {
push @filter_tags, MT::Tag->normalize($_)
foreach @filter_vals;
}
my @tags = MT::Tag->load( { name => [@filter_tags] },
{ binary => { name => 1 } } );
my @tag_ids;
foreach (@tags) {
push @tag_ids, $_->id;
if ($normalize) {
my @more = MT::Tag->load(
{ n8d_id => $_->n8d_id ? $_->n8d_id : $_->id } );
push @tag_ids, $_->id foreach @more;
}
}
@tag_ids = (0) unless @tags;
$arg{'join'} = MT::ObjectTag->join_on(
'object_id',
{
tag_id => \@tag_ids,
object_datasource => $pkg->datasource
},
{ unique => 1 }
);
}
…中略…
}
…後略…
「n8d_id」は半角記号を除去して正規化したデータ。タグ作成時にDBに登録されている。
3.Movable Type 5.1について
Movable Type 5.1でのフィルタリングには「あいまい検索」という項目がありませんが、タグでフィルタリングすればデフォルトの動作であいまい検索を行うようです。
- Movable Typeでタグのインクリメンタルサーチを実現する
- Movable Typeの検索フォームでタグ検索をする
- Movable Typeのテンプレートタグにおけるプライベートタグの正しい指定方法
- タグ別ブログ記事一覧
- Movable Type 5.0 のタグクラウドについて
- ウェブページで画像の出力を制御する
- 特定のランクのタグだけを表示する
- プライベートタグで特定のブログ記事一覧を表示する
- タグクラウドの折りたたみ for Movable Type 4
- タグ検索でエントリーの画像を表示する
- Movable Type 3.3 エントリー・タグ詳説