Home » July 2005 » TagwireとMT-XSearchによる動的タグアーカイブ

TagwireとMT-XSearchによる動的タグアーカイブ

Tags Pluginがサポートする静的なタグ(カテゴリー)アーカイブの代わりに、Tagwire PluginはTim AppnelのMT-XSearchを用いた動的タグアーカイブ機能を実現しています。一般的に言って動的タグアーカイブは、静的アーカイブに比べて生成速度の点で劣りますが、より柔軟なアーカイブ生成がサポートできるという望ましい性質も持っています。例えば、Tagwireでは指定された複数のタグを持つエントリーだけをリストする機能を提供しています。

このエントリーでは、Tagwire PluginをMT-XSearchと組み合わせて動的タグアーカイブを実現する方法とその高速化手法について述べます。


セットアップ方法

すでにTagwire Pluginはインストール済みとします。

  1. MT-XSearchをインストール:
    まず、mt-plus-1.01.zipをDownload mt-plus | Appnel Internet Solutionsからダウンロードし、パッケージに含まれている以下のファイルをMovable Typeのディレクトリにアップロードないしコピーします。
    • mt-xsearch.cgi (実行権限が必要)
    • plugins/mt-xsearch.pl
    • extlib/MT/XSearch.pm
  2. mt-xsearch.cgiとplugins/mt-xsearch.plに以下のパッチを当てます。これはMT-XSearchの多言語対応とバグフィックスのためで、将来のMT-Plus/MT-XSearchのリリースではこのパッチ内容が反映されている可能性があります。
    --- mt-xsearch.cgi.bak	Fri Aug 27 12:06:24 2004
    +++ mt-xsearch.cgi	Sat Jun 11 02:58:33 2005
    @@ -41,7 +41,8 @@
         $ctx->stash('CGI',$q);
         my $out = $tmpl->build($ctx)
             or die "Building search template failed: ".$tmpl->errstr;
    -    print $q->header.$out;
    +    my $charset = $mt->{cfg}->PublishCharset;
    +    print $q->header(-charset=>$charset).$out;
     };
     if ($@) {
         print "Content-Type: text/html\n\n";
    
    --- plugins/mt-xsearch.pl.bak	Sat May 14 06:01:19 2005
    +++ plugins/mt-xsearch.pl	Sat Jun 11 00:31:39 2005
    @@ -63,7 +63,7 @@
         my $pages = $limit ? ($count-($count % $limit)) / $limit : 1;
         $pages += ($limit && $count % $limit) ? 1 : 0;
         my $offset = $xsearch->args->{offset} || 0;
    -    my $current = $offset / $limit + 1;
    +    my $current = $limit ? ($offset / $limit + 1) : 1;
         $ctx->stash('MT::XSearch::current_page',$current);
         $ctx->stash('MT::XSearch::pages',$pages);
         my $builder = $ctx->stash('builder');
    
  3. 「XSearch Tagwire」という名前のテンプレートモジュールを作り、以下のように記述します。
    <html>
    <body>
    <form method="get" action="<$MTCGIPath$>mt-xsearch.cgi">
    <input type="hidden" name="blog_id" value="<$MTBlogID$>" />
    <input type="hidden" name="search_key" value="Tagwire" />
    <label for="search" accesskey="4">Search this site:</label>
    <input id="search" name="search" size="20" value="<$MTSearchString decode_url="1" encode_html="1"$>" />
    <input type="submit" value="Search" />
    </form>
     
    <MTSearchResults>
    <MTSearchHeader>
    Results found: <$MTSearchResultCount$> 
    <ol>
    </MTSearchHeader>
    <li><a href="<$MTEntryLink$>"><$MTEntryTitle$></a></li>
    <MTSearchFooter>
    </ol>
    <p>Searched on: <em><$MTSearchString decode_url="1"$></em></p>
    </MTSearchFooter>
    </MTSearchResults>
    <MTNoSearch><p>No search performed.</p></MTNoSearch>
    <MTNoSearchResults><p>Nothing found.</p></MTNoSearchResults>
     
    </body>
    </html>
    
    このテンプレートは一例で、好みに応じてカスタマイズすることができます。

使い方

タグ検索フォーム:

タグ検索用のフォームを生成するには、インデックス/アーカイブテンプレートに以下のように追加します。

<form method="get" action="<$MTCGIPath$>mt-xsearch.cgi">
<input type="hidden" name="blog_id" value="<$MTBlogID$>" />
<input type="hidden" name="search_key" value="Tagwire" />
<label for="search" accesskey="4">Search this site:</label>
<input id="search" name="search" size="20" value="<$MTSearchString decode_url="1" encode_html="1"$>" />
<input type="submit" value="Search" />
</form>

タグアーカイブリンク:

フォームを生成せずに特定のキーワードの検索結果へのリンクを直接作ることもできます。

<MTEntryTags glue=", ">
<a href="<$MTCGIPath$>mt-xsearch.cgi?blog_id=<$MTBlogID$>&search_key=Tagwire&search=<$MTTag encode_url="1"$>"><$MTTag$></a>
</MTEntryTags>

より簡便なタグアーカイブリンク:

「http://my.host.tld/tag/Tag」のように簡便な形式のURLでタグアーカイブにアクセスできるようにするには、以下のように.htaccessに追加します。

RewriteEngine on
RewriteRule ^tag/(.*)$ /mt/mt-xsearch.cgi?blog_id=1&search_key=Tagwire&search=$1 [QSA,L]

この設定を行っておけば、タグアーカイブへのリンクは以下のように書くことができます。

<MTEntryTags glue=", ">
<a href="<$MTBlogURL$>tag/<$MTTag encode_url="1"$>"><$MTTag$></a>
</MTEntryTags>

詳しいオプション

タグ検索フォームのフィールド、もしくはタグアーカイブリンクのQuery Stringに追加可能なオプションは以下に示す通りです。

blog_id (REQUIRED)
検索対象となるブログIDを指定します。
search_key (REQUIRED)
"Tagwire"という固定の文字列を指定してください。
search (REQUIRED)*1
URLエンコーディングされた検索文字列を指定します。delimiter(区切り文字)で区切られた一個以上のタグを指定できます。複数のタグを指定した場合には、MT-XSearchはそれらすべてをタグとして持つエントリーのリストを生成します。
delimiter*1
検索文字列のdelimiter(区切り文字)を指定します。デフォルトのdelimiterは空白文字(URLエンコーディングでは%20または+)です。
case_sensitive [0 | 1]
キーワードの大文字・小文字を区別するかどうかを指定します。デフォルトでは区別します(case_sensitive="1")。
sort_order [ascend | descend]
リストアップする順序を昇順(ascend)か降順(descend)かを選択します。デフォルトでは降順(descend)です。

*1 searchオプションとdelimiterオプションの関係が分かりやすいように以下では例を挙げます:

  • searchに"movable+type"を指定し、delimiterを省略した場合:
    "movable"と"type"というタグを持つエントリーのリストが生成されます。
  • searchに"movable,type"を指定し、delimiterに","を指定した場合:
    上と同様、"movable"と"type"というタグを持つエントリーのリストが生成されます。
  • searchに"movable+type,plugin"を指定し、delimiterに","を指定した場合:
    "movable type"と"plugin"というタグを持つエントリーのリストが生成されます。
  • searchに"movable+type,plugin"を指定し、delimiterを省略した場合:
    "movable"と"type,plugin"というタグを持つエントリーのリストが生成されます。

少し進んだ話題: CGI::Cache enabled MT-XSearch

上記で説明した方法ではタグアーカイブにアクセスするたびにCGIプロセスを起動し、DBからタグ情報を取得し、それを結果ページとして表示するため、動作が遅いことは否めません。しかし、タグには滅多に変更がないことを前提にするなら、一定期間検索結果をキャッシュしたり、データの転送を抑制したりすることで大幅なオーバーヘッドの削減が可能になります。

ここではCGI::Cacheを使った高速化方法(CGI::Cache enabled MT-XSearchと呼ぶ)を紹介します。具体的には、検索結果を一定時間(例では1時間)キャッシュし、かつHTTP HeaderのLast-Modifiedにキャッシュした時刻を格納して返します。これによって以下の二つの効果が期待されます。

  • キャッシュを作成してから一定時間内は再検索しないことによる負荷の軽減
  • この期間内に二回以上アクセスするブラウザには304 Not Modifiedを返すことによる、データ転送の削減

CGI::Cache enabled MT-XSearchを実現するには、CPANからCGI::Cacheモジュールをインストールし、以下のパッチをmt-xsearch.cgiに適用します。

--- mt-xsearch.cgi.bak	Fri Aug 27 12:06:24 2004
+++ mt-xsearch.cgi	Sat Jun 11 03:44:32 2005
@@ -17,6 +17,7 @@
 }
 
 use CGI;
+use CGI::Cache;
 use MT;
 use MT::ConfigMgr;
 use MT::Template;
@@ -27,10 +28,13 @@
     my $mt = MT->new( Config => $MT_DIR . 'mt.cfg', Directory => $MT_DIR )
         or die MT->errstr;
     my $q = new CGI;
+    CGI::Cache::setup({ cache_options => { cache_root => './cache', default_expires_in => 3600 } });
     my $blog_id = $q->param('blog_id') or
         die "Missing parameter blog_id";
     my $key = $q->param('search_key') or
         die "Missing parameter key";
+    CGI::Cache::set_key($q->Vars);
+    CGI::Cache::start() or exit;
     my $search = MT::XSearch->execute($q);
     my $tmpl = MT::Template->load( { 
                         name=>'XSearch '.$key, 
@@ -41,7 +45,14 @@
     $ctx->stash('CGI',$q);
     my $out = $tmpl->build($ctx)
         or die "Building search template failed: ".$tmpl->errstr;
-    print $q->header.$out;
+    my $charset = $mt->{cfg}->PublishCharset;
+    my @m = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+    my @w = qw(Sun Mon Tue Wed Thu Fri Sat);
+    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime(time);
+    my $now = sprintf("%3s, %02d %3s %04d %02d:%02d:%02d GMT",
+        $w[$wday], $mday, $m[$mon], $year+1900, $hour, $min, $sec);
+    print $q->header(-charset=>$charset,-Last_Modified=>$now).$out;
+    CGI::Cache::stop();
 };
 if ($@) {
     print "Content-Type: text/html\n\n";

赤字で示した部分はそれぞれ「キャッシュの作成場所」「キャッシュの生存期間」を表します。上記の例ではそれぞれ「mt-xsearch.cgiのあるディレクトリの直下のcacheディレクトリ」「1時間(=3600秒)」を指定してあります。

このエントリーのトラックバックURL: http://as-is.net/mt/mt-tb.cgi/290

Links referred to this entry

Comments (24)

  1. .htaccessへの記述ですが
    key=AllKeywords&search=$1
    ではなく
    key=Tagwire&search=$1
    ですよね?
    これでも動くのかもしれませんが。

  2. ご指摘の通りです。対応しておきました。

  3. tagにスペースを含む文字を使う場合、MT-XSearchがうまくうごいてくれない問題が…。
    drryさんのところでも指摘されてますけど、&delimiter=,をパラメータとして渡してやるとうまくいきました。
    それにしても(o)さんには感謝です。

  4. 申し訳ないですが現状それが仕様なのでいかんともしがたいところです。
    いずれ何らかの注意書きを追加したいと思います。

  5. Tagwire Plugin の記事、とても参考になりました。
    del.icio.usなどを使い始めTagで管理する事の便利さを知って、私のブログにもTagを導入しようと思ったのですがうまく行かない点がありました。

    上記の手順でインストールし、.htaccessを設定して /tag/タグ名 でアクセスしたところ
    『Got an error: Not an ARRAY reference at extlib/MT/XSearch.pm line 88.』
    とのエラーが出ます。

    私の設定が間違っているのでしょうか?
    お手数ですがご返答頂けないでしょうか。

  6. 存在しないタグを指定した場合、そのエラーが表示されるようです。
    近々それを含むバグフィックス版を公開する予定にしています。

  7. 迅速な返答ありがとうございます。

    存在しないタグを指定した場合のエラーとの事で、存在するタグを指定してテストしていたにもかかわらずエラーが出ていたため、設定を確認し再度インストールし直したら動くようになりました。
    お騒がせしてしまいすいませんでした。

    また色々参考にさせて頂きたいと思ってますのでよろしくお願いします。

  8. はじめまして。
    早速Tagwire Pluginを導入したくて昨日から取り組んでいるのですが、何回試しても
    「Got an error: Can't call method "build" without a package or object reference at mt-xsearch.cgi line 42.」
    と表示されてしまいます。
    その語句で検索してみると、テンプレートモジュール(XSearch Tagwire)の名前が間違っている、もしくはモジュールが存在しない時にも出るとの事らしいのですが、テンプレートモジュールを再設定しても同じエラーメッセージがでます。

    他にどのような原因が考えられますでしょうか?
    すいませんがよろしくお願いします。

  9. mt-xsearch.cgiに与えるsearch_keyオプションの値が"KEY"のとき、mt-xsearch.cgiが参照するテンプレートモジュールの名前は"XSearch KEY"とする必要があります。この"KEY"に相当する文字列が両者で一致していない場合にそのエラーメッセージが表示されます。

    それ以外の理由でもそのエラーメッセージが表示される可能性はありますが、現在のところ現象が再現できていません。

  10. Ogawaさん、コメントありがとうございます。
    再設定しどうにか無事表示することができました!
    ただ、.htaccessの設定がうまくいかなかったので小粋空間さんで書かれている方法で対応しました。
    素敵なプラグインを作っていただきありがとうございます!!

  11. [TagwireとMT-XSearchによる動的タグアーカイブ]がやっと!うまく設置できました。
    すばらしい内容、ありがとうございました。

  12. こんにちは。度々すみません。MTEntryTagsのlastnあるいはoffsetオプションについてお聞きしたHANAです。この問題は解決できましたが、CGI::Cacheでつまづきました。キャッシュを使わない状態では正常に動作しますが、キャッシュ用のパッチを当てるとスクリプトエラーになります。 CGI::Cacheに関連するFile::Path、Tie::Restore、File::Spec、Cache::Cache、Storable などもインストールしていますが。。ちなみにバージョンは3.2-ja-2 です。原因について何か考えられますでしょうか?宜しくお願いいたします。

  13. 上記コメントをしたものです。
    CGI::Cacheに関連するモジュールで不足しているものがあり、アップロードすることで解決いたしました。お騒がせいたしまして申し訳ございません。 (ご参考までに上記関連ファイルの他、extlibにError.pmをアップロードしました。)

  14. 安価なレンタルサーバなどでは、必要なPerlモジュールがインストールできない場合がありますから、苦労されただろうなと思います。
    解決して本当によかったですね。

  15. こんばんわ^^

    TagwireとMT-XSearch の記事とても参考になりました。
    わたしはまだ初心者の域を超えていないですが、なんとか設置できたのでよかったです♪

    ありがとうございました。

  16. 多国語支援になって本当にありがたく使っています. 動的タッグarchiveで英文タッグリンクはよくできるが koreanタッグリンクはゴムセックギョルとを表示することができません. どの部分を確認しなければならないか助けをお願い致します. 検索魚倉で koreanに検索する場合には作動がまともにできます.
    http://www.pdaclub.org/blog/tag.html

  17. どうやらハングルのタグの場合に、mt-xsearch.cgiにタグの名前が渡っていないのが問題ですね。Rewrite Ruleを確認してみてください。

    ちなみに私のブログでは、「플러그인」というタグも正しく表示できますよ。
    http://as-is.net/blog/tag/%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8

  18. 本当にありがとうございます. おっしゃってくださったお陰に原因を推測しました. ウェップサーバー問題でした. .htaccessに checkURL Off を追加して解決しました.

  19. 12番目のコメントをさせていただいたHANAと申します。たびたびのご質問で申し訳ないのですが、
    Ogawaさんの検索画面では右側にRelatedを表示されていると思います。例えば、searchに"movable+type"を指定(複数)しているときなど、Related が各々のクエリータグに対して得られる結果となっておりますが、これは特別の書き方をなされていますでしょうか?
    よろしくお願いいたします。

  20. MTXSearchTagsを使って下のように書けますよ。

    <MTXSearchTags>
    <h2>Related Tag: <$MTTag$></h2>
    <ul class="tag-listing">
    <MTRelatedTags>
    <li><a title="Tag: <$MTTag$>"
    href="<$MTBlogURL$>tag/<$MTTag encode_url="1"$>"><$MTTag$></a></li>
    </MTRelatedTags>
    </ul>
    </MTXSearchTags>

  21. Ogawaさま
    ありがとうございます。 MTXSearchTags は複数のクエリに対しても実行されるのですね。例えば、その複数クエリのRelatedを合わせてしまって、重複しないタグはそのまま表示し、重複するタグは1個のみ表示する、というのは可能でしょうか。tagwire.plの修正等になるかとは思いますが。。。

    想像ですが、tagwireに関する下記のコメントあたりにもからみますでしょうか。
    --------------------------------------
    それはですね、技術的にはまったく問題なくできるのですけれど、tagwireが提供するMTタグの命名方法を整理しなくてはいけないのです。今の仕様だとMTTagというタグがどこでも使えますが、 MTEntryTagsの中ではMTEntryTag、MTTagsの中ではMTTag、MTRelatedTagsの中ではMTRelatedTag、という具合に使い分けるように変更する必要があります。
    この変更もいつかやりたいのですが、すべてのユーザーにテンプレートを変更してもらう必要があるので、少し尻込みしているという現状です。
    --------------------------------------

  22. >複数クエリのRelatedを合わせてしまって、重複しないタグはそのまま表示し、重複するタグは1個のみ表示する

    RelatedTagsの振る舞いを変えることもできますが、そうしなくてもCollate Pluginを使えばできますね。

  23. Ogawaさま
    ご指摘ありがとうございます。
    下記のように書くことで可能となりました。

    <MTCollateCollect>
    <MTXSearchTags>
    <MTRelatedTags>
    <MTCollateRecord>~</MTCollateRecord>
    </MTRelatedTags>
    </MTXSearchTags>
    </MTCollateCollect>

    ありがとうございました!

  24. はじめまして、初コメ&質問です。

    .htaccessを新しく作り、上の解説の通りに

    RewriteEngine on
    RewriteRule ^tag/(.*)$ /mt/mt-xsearch.cgi?blog_id=1&search_key=Tagwire&search=$1 [QSA,L]

    を書いて保存し、それ以降の手順も済んだのですが、どうもこのファイルが機能していないらしく、リンクをクリックした際に、エラー404が発生してしまいます。

    .htaccessはmt.cgiと同じディレクトリに保存してますが、これは正しいですか?いろいろいじってみたんですが、さっぱりわかりません。
    よろしくお願いします。

Post a comment

Remember me?