Movable Typeのタグの「あいまい検索」について

Movable Typeのタグの「あいまい検索」について

Posted at April 26,2011 1:55 AM
Tag:[MovableType, Tag]

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テーブルを表示したものです。

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 5.1

関連記事
トラックバックURL


コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)