Mar 27, 2005

AllKeywords Plugin とMT-XSearchの連携

AllKeywords PluginはTagwire Pluginに開発が引き継がれました。下記のエントリーをご参照ください。

AllKeywords Pluginは、エントリーのキーワード部分をハンドリングするための機能を追加するだけでなく、MT-XSearchと連携して軽量なキーワードサーチを行うための機能も持っている。キーワードサーチはMovable Typeに付属しているmt-search.cgiを改造することもでも実現できるが、改造してしまうと他の用途に利用できないというデメリットもある。一方、MT-XSearch*1はさまざまな検索サービスを追加できるフレームワークで、どのような検索を実現するかはプラグインとして分離することができる。AllKeywords Pluginはその一例となっている。

このエントリーではAllKeywords PluginとMT-XSearchとの連携方法とその高速化手法について述べる。

*1 Tim Appnelの作。昨年のDevelopper's Contestの受賞作の一部で、Movable Typeに拡張性のある検索サービスを追加するためのフレームワーク。運悪くmovabletype.org : Developer's Contest Plugin Pack: 2004のページからplugin packへのリンクがなくなっており、Appnelも(パッチは公開しているが)公開していないので現在Webでは入手不能。公開してくれよとは言っているのだが...。そういうわけで残念ながらAllKeywords Pluginの連携機能の効果は限定的なものとなる。

2005-06-11追記: MT-XSearch自体はDownload mt-plus | Appnel Internet Solutionsから入手できる。

連携方法

すでにAllKeywords Pluginはインストール済みとする。

  1. MT-XSearchをインストールする。具体的にはプラグインパッケージに含まれるMT-XSearch0.3.zipmt-plus-1.01.zipをアンパックしてその中のmt-xsearch.cgi、plugins/mt-xsearch.pl、extlib/MT/XSearch.pmをそれぞれ適切なディレクトリにアップロードする。mt-xsearch.cgiはCGIとして実行できるように実行権限を与える必要がある。
  2. mt-xsearch.cgiはそのままでは日本語がうまくハンドリングできないので、以下のパッチを当てる。
    --- 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";
    
  3. 2005-06-11追記: plugins/mt-xsearch.plはそのままではdivision by zeroエラーが起きるので、以下のパッチを当てる。
    --- 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');
    
  4. 「XSearch AllKeywords」という名前のテンプレートモジュールを作り、例えば以下のように記述する。
    <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="AllKeywords" />
    <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="AllKeywords" />
<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>

また、以下のようにフォームを生成せずに特定のキーワードの検索結果へのリンクを作ることもできる。

<$MTCGIPath$>mt-xsearch.cgi?blog_id=<$MTBlogID$>&search_key=AllKeywords&search=Blog

.htaccessに以下のように記述すれば、「http://blog.your.domain/tag/Keyword」のように簡便なURLで特定のキーワードの検索結果を得られる。

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

以下は2005-06-11に追記したものです。

高速化の方法

上記で説明した方法ではリクエストのたびにCGIを起動し、検索結果を取得して表示しているため、動作が遅いことは否定できない。しかしタグには滅多に変更がないことを前提にするなら、一定期間検索結果をキャッシュしたり、データの転送を抑制したりすることで大幅な高速化が可能になる。

ここでは手っ取り早くCGI::Cacheを使って高速化を実現する方法を紹介する。具体的には、検索結果を一定時間(例では1時間)キャッシュし、なおかつHTTP HeaderのLast-Modifiedにキャッシュした時刻を格納して返す。つまり、以下の二つの効果が期待される。

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

方法は単純で、CPANからCGI::Cacheモジュールをインストールし、「連携方法」の2.で示したパッチの代わりに以下のパッチをmt-xsearch.cgiに適用するだけでよい。赤字で示した部分はそれぞれ「キャッシュの作成場所」「キャッシュの生存期間」を表す。下記の例ではそれぞれ「mt-xsearch.cgiのあるディレクトリの直下のcacheディレクトリ」「1時間(=3600秒)」を指定してあるので必要に応じて変更するとよい。

--- 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";

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

Copyright 2012 Ogawa::Buzz | Powered by Blogger
Design by Web2feel | Blogger Template by NewBloggerThemes.com