Jul 31, 2005

東京ドームで野球を観る

金曜日のことですが、東京ドームで読売対中日ドラゴンズ11回戦を観てきました。

2005シーズン 公式戦/試合結果

川上憲伸が2安打1四球に抑えて完封、自身も今季初のホームランを打つという(私を含めて)ドラゴンズファンにとっては言うことのないゲームでした。

さて今年に入ってから二度ほどボールパークに足を運んでいる私ですが、去年まではほとんど行ったことがありませんでした。野球のチケットは手に入りづらいものだと思い込んでいたのですが、直前であってもローソンチケットやらe+やらで思いのほか、というか夏休みにも関わらず読売のゲームのチケットが2日前でも余裕で買えるという程度には、簡単に手に入ることが分かってしまいました。2時間で1800円の映画に対して、3~4時間3~4000円でそこそこの席で見られる野球はなかなかお手軽な娯楽だな、と認識を改めている次第。

翻ってテレビ放送の方に目を移すと、視聴率5%台でポケモンに負けたとかセンセーショナルな報道がなされる一方で、ちょっとは信用できそうなデータ(Video Research Ltd. 視聴率 > プロ野球 > プロ野球 巨人戦・月平均・年間平均)によると単に低下傾向が維持されているだけというのが実際のところのようです。特に読売は99年~02年に優勝争いに絡んでいたはずですが、にも関わらずその間の視聴率の低下は顕著なものがあり、読売の成績や人気との因果関係よりは視聴者の行動様式(例えば贔屓のチームの負け試合は観ずにビデオでも観る)との関係がより強く想定されるわけです。まあそれはそれで良いのではないか、と。コンテンツの改善によって抗い得る問題でもないわけですし。

Jul 30, 2005

"Subscribe with Feedbringer" Bookmarklet

RSSリーダーFEEDBRINGER.net、良いですねー。Bloglinesのもっさりさ加減に比べると非常に快適です。

「FEEDBRINGER」はかなりおすすめ!! : 亜細亜ノ蛾 - Weblog
the meager: FEEDBRINGER

私の方からは以下のリクエストを出しておきました。

  • フィードの表示順がアイテムの作成時刻の昇順に固定されていますが、これを降順にも変更できるようにしてください
  • CrawlerのUser-Agentに「FEEDBRINGER/0.1 (http://feedbringer.net/; XX subscribers)」のようにsubscribe countをいれてください

それにしてもOPMLを共有するサービスというのを誰かやらないものでしょうか。現状データ形式しか定義されていないわけですが、その上に操作用のプロトコルを定義してそれをサービスとして提供してくれれば、一箇所で行ったブックマークへの更新が他のところでも(デスクトップでも)反映されたりするわけです。ときどき広告表示用のブックマークを挿入しさえすればビジネスモデル的に成立しますよね。

それはともかく、「Subscribe with Feedbringer」Bookmarkletです。

Subscribe with Feedbringer

上記の「Subscribe with Feedbringer」リンクをブラウザのメニューバーなどにDrag&Dropするか、右クリックで「お気に入りに追加」するかしてBookmarkletとして保存するとよいでしょう。

2005-08-05追記: 本家にも同じようなの用意されましたね。それとも気が付かなかっただけで最初からあったのかしら...。でも本家版だとURLに&などを含むときに正しく動作しないと思うんですけどね。

2005-08-19追記: 本家のBookmarkletもencodeURIComponentするようになりました。またリクエストしていた点が改善されましたね。あとFeedburnerでFeedbringerのsubscribers countが反映されないみたいなので、そっちのフォーラムに書き込んでおきました。
FeedBurner Support :: View topic - Some minor online RSS readers

Jul 27, 2005

Pin It On The Earth!: Googleマップで閲覧中の地点を Google Earth にマップするBookmarklet

Google マップの任意の地点を閲覧中に、その地点に対応するGoogle Earth上の地点を表示するBookmarkletを作ってみました。具体的にはGoogleマップから得られる緯度・経度情報を使って、gmaps2kml.cgiでKML(Google Earth KML Documentation)を生成し、それをGoogle Earthが読み込んでPlacemarkとして表示するというシカケです。もちろんKMLファイルとして保存してWebページで公開したりする目的にも使用できます。

測地系の変換には、Nowral様(02 DATUM)の「測地系パラメタを使う方法」のスクリプトを利用させていただきました。

Pin It On The Earth! (2005-07-31更新)

上記の「Pin It On The Earth!」リンクをブラウザのメニューバーなどにDrag&Dropするか、右クリックで「お気に入りに追加」するかしてBookmarkletを保存します。

使い方

  1. GoogleマップでGoogle Earthにマップしたい場所を表示し、メニューバーの「Pin It On The Earth!」Bookmarkletをクリックします。

  2. 説明を入力するためのプロンプトが表示されるので入力します。デフォルトではBookmarkletを実行したウィンドウのタイトルが入力されているので適宜書き換えてください。

  3. ほどなくファイルをGoogle Earthで開くかどうか聞かれるので開きます。下の画像は英語版のFirefoxでの表示です(ブラウザによって表示は異なります)。

  4. (゚Д゚)ウマー

    メイン画面にはGoogleマップで見ていた場所が表示され、左側のPlacesメニューのTemporary Placesにその場所が追加されます。

注意点

  • 外部のページを呼び出している関係上、Microsoft Internet Explorer 6 SP2などでは警告が出てうまく使えない可能性があります。回避する方法はありますが説明は省略します。

更新履歴

2005-07-27 16:23 (Pin It On The Earth!)
  • とりあえず公開。
2005-07-31 00:24 (Pin It On The Earth!)
  • プロンプトを表示してPlacemark用ラベルを入力できるように動作を変更。

gmaps2kml.cgiについて

gmaps2kml.cgiは「ll=緯度(10進),経度(10進)」というオプションを与えるとKMLを返す単純なCGIスクリプトです。Googleマップに限らず汎用に使えます。

デフォルトでは与えられた緯度が30~50度かつ経度が115~152度のとき、日本測地系(Tokyo)のデータとみなしてWGS 84測地系に変換してKMLを出力します。それ以外のときは変換せずに出力します。「mode=tky」というオプションを与えると緯度・経度に関わらず日本測地系(Tokyo)のデータとみなしてWGS 84測地系に変換してKMLを出力します。「mode=wgs」というオプションを与えると緯度・経度に関わらずWGS 84測地系のデータとみなして変換せずにKMLを出力します。

その他のオプション:

  • r=URL
    Google EarthのPlacemarkからそのURLへのリンクを生成することができます。このオプションが指定されると、以下のdescription要素を含んだKMLが出力されます。
    <description><![CDATA[<a href="URL">Original Map Location</a>]]></description>
    「Pin It On The Earth!」Bookmarkletでは座標情報の取得に用いたURLが格納されるようになっています。
  • t=String
    Placemarkの表示名を設定することができます。このオプションが指定されると、以下のname要素を含んだKMLが出力されます。
    <name>String</name>
    デフォルトでは「Pin It On The Earth!」という文字列が設定されます。

ちなみに、llオプションを与えない場合にはGoogle Maps APIを使って表示された地図上の点からKMLを生成することができます。一般的にはこっちの方が有意義なのかな?

Jul 26, 2005

Tagwireでタグクラウドを実現する

Tagwire Pluginでは、ブログで使用しているすべてのタグをリスティングする機能を持ちます。また、その際にタグの名前以外にタグの使用個数、タグの最終利用時刻を取得することができます。

したがって、タグの一覧を表示する際に使用頻度に応じてサイズを変更するとか、タグの最終利用時刻に応じて濃淡を変更するとか、当然ですがそういうことは普通にできます。search.cpan.org: HTML::TagCloud - Generate An HTML Tag Cloudに食わせる用のデータを作るもよし、タグデータと表示用の処理を含むJavascriptを生成するのもよし、タグデータXMLを生成してえーじゃっくすでほげほげするもよし、まあ好きなように使えます。

ここでは私のTagCloudのページのテンプレート(抜粋)を貼り付けておきます。ときどきソースをくださいと言われるので。少し変更すればTags Pluginなどにも転用できます。

<style type="text/css">
ul#tags { border: 1px solid #CCC; padding: 10px; margin: 10px; display: none; }
#tags li { display: inline; }
#tags li a { border-width: 0; color: #000; }
#tags li.hot a { color: #00F; }
#tags li.old a { color: #777; }
#tags li.oldest a { color: #CCC; }
#tags li a:active, #tags li a:hover { color: #6C3; }
.coffButton { color: #000; background: #fff; border: 1px solid #ccc;
  padding: 2px; cursor: pointer; }
a.coffButton:hover { color: #000; background: #ccc; }
#coff { font-weight: bold; padding: 2px; }
</style>
<p>
Cutoff Parameter:
<a onclick="decCoff(5)" class="coffButton">-5</a>
<a onclick="decCoff(1)" class="coffButton">-1</a>
<a onclick="incCoff(1)" class="coffButton">+1</a>
<a onclick="incCoff(5)" class="coffButton">+5</a>
<span id="coff">0</span>
</p>
 
<ul id="tags">
<MTTags>
<li title="<$MTTag$>:<$MTTagCount$>:<$MTTagDate format="%Y-%m-%d"$>"><a
 title="Tag: <$MTTag$>" 
 href="<$MTBlogURL$>tag/<$MTTag encode_url="1"$>"><$MTTag$></a></li>
</MTTags>
</ul>
 
<script type="text/javascript">
function calcFontSize(count) {
 return count / 6 + 12;
}
var tags = new Array();
var now = (new Date()).getTime();
var tagsNode = document.getElementById('tags');
var childNodes = tagsNode.childNodes;
for (var i = 0; i < childNodes.length; i++) {
  var e = childNodes.item(i);
  if (e.nodeName.match(/li/i)) {
    var s = e.title.split(':');
    e.style.fontSize = calcFontSize(s[1]) + 'px';
    var d = s[2].split('-');
    var diff = (now - (new Date(d[0], d[1] - 1, d[2])).getTime()) / 86400000;
    if (diff < 14) e.className = 'hot';
    else if (diff > 365) e.className = 'oldest';
    else if (diff > 60) e.className = 'old';
    tags.push([ e, s[1] ]);
  }
}
tagsNode.style.display = 'block';
 
var coff = 0;
var coffNode = document.getElementById('coff');
function decCoff(c) {
  if (coff == 0) return;
  coff -= c;
  if (coff < 0) coff = 0;
  coffNode.innerHTML = coff;
  refreshCoff();
}
function incCoff(c) {
  if (coff == 20) return;
  coff += c;
  if (coff > 20) coff = 20;
  coffNode.innerHTML = coff;
  refreshCoff();
}
function refreshCoff() {
  for (var i = 0; i < tags.length; i++) {
    var tag = tags[i];
    tag[0].style.visibility = (tag[1] <= coff) ? "hidden" : "visible";
  }
}
</script>

要はTagCloudに必要な情報をあらかじめ生成してタグをwrapしている要素のtitle属性に突っ込んでおき、Javascriptを使ってその情報を見た目に反映させています。ちなみにこの例では、使用頻度に応じてサイズを変更している他に、2週間以内に更新されたタグはブルーで、更新されてから60日以上経ったタグはグレーで、一年以上経ったタグはより薄いグレーで、それぞれ表示しています。

Jul 21, 2005

Hokey Pokey Icecream

今から遡ること10数年前、家族旅行でニュージーランドに行ったのだが、その折随行していたガイドの人が強力に我々に薦めていたのが、Hokey Pokey Icecream。ニュージーランドのアイスクリーム屋ならどこでも食べられるという触れ込みだったのだが、それらしいものは見つからず結局食べられずじまいで帰国の途についたのだった。

食べられなかったのがよほど悔しかったのか執念深くもその名前を記憶し続けていた私だったのだが、今頃になって近所の大丸ピーコックで扱っているのを発見し、竹馬の友に再会したような気分に七秒ほど浸ってみた。株式会社アイガー 冷凍デザート部(京都府久世郡久御山町下津屋北野35-4)というところが輸入・販売していらっしゃるご様子。

なんのことはない、Hokey Pokeyとはキャラメルの粒のことを意味しているらしく、Hokey Pokey Icecreamとは、このキャラメルの粒がニュージーランドの強烈に甘いバニラアイスクリームにまぶしてあるものだった。確かにおいしい。けど甘すぎるので冬食べた方がよいかもしれない。

ちょっと感動したのは、この(株)アイガー 冷凍デザート部はオンラインショップもやっており、日本全国津々浦々北は北海道から南は沖縄までこの激甘ワールドを楽しめるようになっているということだ。

EIGER|アイスクリーム

なっているということだが…。1個5040円? ちょっと高い? というか高過ぎな感じ。

よくよく見ると1リットルのパッケージ12個単位でしか注文できないという「プロ仕様」のオンラインショップなのでした。冷凍庫の容積に自信がある方は試してみては、とナゲヤリに薦めてみたり…。

Jul 17, 2005

Pin It!: Googleマップで任意の場所にピンを立てるBookmarklet

HepCat Dev and Test: Googleマップの好きな場所に好きな文字で噴出しピンを立てるに触発されて、Google マップの任意の場所に任意の文字列付きで噴出しピンを立てるBookmarkletを作ってみました。

Pin It!

上記の「Pin It!」リンクをブラウザのメニューバーなどにDrag&Dropするか、右クリックで「お気に入りに追加」するかしてBookmarkletを保存します。

使い方

  1. Googleマップでピンを立てたい場所を表示し、メニューバーの「Pin It!」Bookmarkletをクリックします。

  2. 説明を入力するプロンプトが表示されるので入力します。

  3. (゚Д゚)ウマー

  4. ここでQuickPostとかするとさらに(゚Д゚)ウマー

更新履歴

2005-07-17 00:01 (Pin It!)
  • とりあえず公開。
2005-07-17 03:19 (Pin It!)
  • 「このページのリンク」のURLから位置情報が得られない場合には何もしないように動作を変更。
2005-07-20 14:44 (Pin It!)
  • nirvashさんのご指摘を反映。
  • 生成されるURLが冗長だった(llオプションは意味がない)のを修正。
2005-07-21 21:59 (Pin It!)
  • Googleマップ以外のページで利用したときのWarningを抑制。
  • Descriptionを入力しなかったときのエラーを抑制。
2006-02-16 15:50 (Pin It!)
  • いつの間にやら使っていた要素のidが変わっていたので修正。

TODO

  • 「このページのリンク」のURLから位置情報が得られない場合の対策。window.document.vpageに格納されている位置情報が使えるような予感が...。やっぱりムリポ。

Jul 16, 2005

mt-db-convert.cgi: MTデータベースの相互変換 CGIスクリプト

Movable TypeのデータベースをDB間で相互にコンバートするCGIスクリプトを公開します。

MT_Database_Converter - ogawa - Google Code

Movable TypeのデータベースをBerkeleyDB、MySQL、PostgreSQL、SQLiteの間で相互に変換するCGIスクリプトです。テスト環境から本番環境への移行、プラグインの開発、そしてDBのアップグレードなど、データベースを一方から他方に移行したい場合に役に立ちます。DB間の相互変換は、従来からMovable Typeに付属しているmt-db2sql.cgiと拙作のOgawa::Buzz: mt-sql2db.cgi: mt-db2sql.cgiの逆変換CGIスクリプトを組み合わせれば実現できましたが、このスクリプトはそれを単体で実現します。また、mt-sql2db.cgiにあったバグをいくつか修正してあります。

今年の3月くらいには作ってあったのですが、mt-db2sql.cgiのコードを再利用しているので公開を見送っていました。この度ようやくSix Apartの言質が取れたので公開する次第です。

Jul 8, 2005

今こそnofollow属性を有効にしよう

今月になってGoogle経由でのアクセスが大幅に減少したブログが多数あるようです。PageRankに変更があったためですが、その原因をGoogleの特許出願*1が実装されたせいだと(あまりその内容を吟味することもなく)早とちりしたり、トラックバック元の言及リンクがないせいだと誤解したりする人がまた非常に多いようです。

*1 Googleの新しい順位決定方法のすべて。SEO関係者必読、グーグル特許出願文書全訳 [絵文録ことのは]2005/07/01

Googleが具体的にどの程度あるいはどのように出願内容を実装しているのかは一切不明ですが、トラックバックリンク(外部にトラックバックを送った時に生成されるリンク)に対応するバックリンクがないとトラックバック受信側のPageRankが下がるなどとは一言も書かれていません。書いてあるのは、トラックバックリンクの効果が、履歴情報や、送信側と受信側の内容の関連の有無などによって低減され得るということです。つまり、スパミング行為によって一時的に大量のトラックバックリンクを獲得したり、関連性のないページからのトラックバックリンクを獲得したりしても効果がないようにしようということです。

一方で今回のPageRankの低下は、単純に外部へ送ったトラックバックによってかさ上げされていたPageRankが出願方式およびnofollow属性によって無効化、あるいは適正な水準に是正された影響だと捉えると納得しやすいでしょう。

また、外部からのトラックバックによる受信側のPageRankへの影響は(そもそも出願内容に受信側への影響に関する言及はありませんが)、nofollow属性を付与していさえすれば排除できます。排除できるのであれば、トラックバック送信側のページに言及リンクがあるかどうかは一切関係ありません。

結局のところ私が言いたいのは、

  • まずはnofollow属性を有効にしましょう。
  • naoyaのはてなダイアリー - Movable Type で言及リンクのない TrackBack ping を弾くプラグインゑBLOG: トラックバックSPAM防止プラグイン自身にPageRankを向上させる効果はありませんし、トラックバックの受信速度を低下させるだけです。言及リンクを含んだトラックバックしか受信できなくなることによって受信側への言及リンクが増え、よりPageRankが上がるような気がするかもしれませんがそうではありません。実際に観測される現象は、トラックバックの受信に失敗しやすくなってスパム・ハム(非スパム)の両方とも件数が減るというものでしょう。言及がないトラックバックをとにかく受け入れたくないという場合にはインストールするとよいでしょう。
    2005-07-14追記: 私自身はそういう意図ではありませんでしたが両プラグインに意味がないという誤解を招く表現になっていました。両プラグインの作者さまには謹んでお詫び申し上げるとともに、今後は誤解を招かないように心がけたいと思います。
  • 役に立つエントリーを書いて外部から多く言及されるようにしましょう。そうすることが一旦落ちたPageRankの回復に繋がります。

ということです。

Jul 2, 2005

言及したら負けかなと思ってるトラックバックの話

言及したら負けかなと思ってる

のだが(参考)、トラックバックが言及リンクを含まなければならないという気分が醸造(情造)されてきているようだ。それはそれで面白いのだが、嘆かわしいことでもある。

↓の記事を書いた意図の一つは(というか書きかけだが)、トラックバックという機構とその役割を分離して考えられない人々への戒めでもあった。

繰り返すことになるが、トラックバックはショートメッセージを送受信して保存する機能であり、一義的な効果はNotificationであって、Back Linkの生成ではない。それをどのように利用するかは自明に受信側アプリケーション、受信者の裁量である。つまりは、自動的に自分のブログに表示しても、表示しなくても、寛容に受けれても、激怒しても、それは自由である。

ただ、激怒している人に問いたいのは、あなたは新聞の勧誘員や間違い電話やスパムメールに対しても全身全霊をもって怒りをぶつけるような、そんな「美味しんぼ」の登場人物のように熱い、そして暑苦しい人なのですか、ということなのである。私なら黙ってスルーするけど。激怒に加えて面罵した結果、ブログを止めてしまった人もちらほら見かけるわけで、むしろエゴを貫き通した結果周りに迷惑をかけているのではないかと自省しても損はないくらい。私の言葉とも思えないが、所詮実社会と同様他人に優しく自分に厳しくないと円滑な意思疎通は望めないし、みんなもっと眞鍋かをりから学ぶことがあるように思う。


さてここからが本文なのだが、言及リンク派の人々に聞きたいのは「言及リンク」が何で、それを求めることに意味があるかということだ。

ショートメッセージの中身に「言及リンク」を含むことはできないわけだから、ショートメッセージのurlフィールドが指し示すオブジェクトに含まれるa href要素を指していることくらいは容易に想像が付く。しかし、そもそもオブジェクトがHTML文書でない場合にはa href要素は定義されない場合の方が多い。また、仮にオブジェクトがHTML文書だったとしても、(URLとそのトラックバックインタフェースの関係がルーズなのと同程度には)urlフィールドの内容とそこに含まれるリンクの関係はinconsistentで、いつでも好きな時に好きな方法で関連付けを解消・削除できる。また、Basic認証などが施してあって受信側アプリはアクセスできないが人(ブラウザ)はアクセスできるとか、人によって異なる結果を与えるとか、時間の経過とともに異なる結果を与えるとか、非対称性は簡単に作り出せる。極端な言い方をすれば、ショートメッセージとしての用を成しさえすれば、urlフィールドはトラックバック受信側の実装次第では省略できるし、望ましくはないが意味のないものであってもよい。

つまりは、TrackBack Technical Specification自体に定義されていない言及リンクの普遍性は人々が信じるほど確実でない。ちょうど同仕様で定義されているurlからトラックバックインタフェースを自動的に検出する方法が確実であるのとは対照的に。

また、トラックバックの結果生じるリンクと言及リンクによって「相互に等価に」読者の誘導が行われるべきという観点で論じている例も見かけるが、この種の定性的な議論はあまり意味をなさない。なぜなら、Webのリーチのほとんどが検索エンジンやRSSリーダーなどの何らかのアグリゲータに依存していることに加え、トラックバックリンクに比べて直接言及されているリンクがクリックされる確率の方が十分高いと想像されるからである。個人的にはトラックバックをトラックするよりはコメント欄を読む方を好むし、コメント欄にURLがあればトラックバックよりは優先的にトラックする。無論コンテキストが明確だからである。

このように効果が現実には十分に小さいと予測される、あるいは計量可能でない以上、トラックバックはより直截的に著者本人へのメッセージングと同等な意味しか持たないか、それに漸近すると考えるべきである(もちろん過度な一般化は避けるべきだが)。

それでもPagerankが平等に配分されない(?)ことに疑問を呈する向きがあるかもしれないが、その点では言及派の旗色は一層悪いと言わざるを得ない。Nofollow属性によってトラックバックリンクはPagerankの算出に使われないようになる(なった?)以上、言及リンクを求めることは一方的に自分のPagerankを上げることだけを他者に求めていることに等しい、浅ましくも。まあそれを言うなら「トラックバック返し」とかいうのは本当に貧乏くさい発想である。また、「情報ハブ」のPagerankが上がらないからという主張も論理的におかしい、と真のモヒカン族としては指摘しておきたい。なぜなら、情報ハブのPagerankを上げる仕組みをトラックバックで担保しなければならない道理はないからである。

それでも言及リンクを求めることに何か意味があるのだろうか?

…意味がないと言いたい。断言したい。だいたい言及の有無とURLの指し示す情報の持つ価値の大小とは相関しないではないか。

私個人はどのようなトラックバックもウェルカムだし、広報目的も含めてありとあらゆる活用の可能性を否定しないつもりである。そもそもTrackBack Technical Specificationに明示的に言及リンクを含むことが記述されていない以上、それは含まなくてもよいこと、含む必要がないことを意味する。また、仕様書がどうあれ一旦道具が発明されればそれが目的外に使用されることは常にある。言及リンク派がなぜそのことを容認できないのかまったく理解できない。少なくとも私にとって、このトラックバックというゲームの本質は自分側の知りうる情報の量を最大化することにあり、「言及されたこと」を「知る」というのはそのほんの一部に過ぎないか、あるいはまったく情報として価値がない(そんなものはTechnoratiに行けば二束三文で売っている)。

ついでに、言及リンク派は「ディープリンク反対」反対派(ディープリンク擁護派?)を兼ねていることが多いようなのだが、そのことにも私は納得が行っていない。つまり、「ディープリンク反対」というごく情緒的なローカルルールは否定するのに、「言及リンクなしのトラックバック反対」というごく情緒的なローカルルールは肯定するという首尾一貫性のなさに。いやしくもモヒカンの一員を名乗るのならば、主張の一貫性を保つべきことは当然として、技術で克服できないものはないもないと放言して憚らないだけの気概が必要だろう。

最後に誤解を招かないように補足すると、規格準拠性という点ではQuasi-Spam Filter Pluginのようなツールも、言及リンクを必須とする方式もともに規格外である。ただ、前者は規格に準拠して受信したトラックバックをheuristicsに基づいて削除することを手助けするだけである。当然それがユーザーと合意されているからこそ、またその場合にのみ、意味を持つ。同様のことが後者にも言えるのだが、heuristicsとしての根拠と妥当性に疑問があり、本来の目的を損ねる危険性がごく高い。

2005-07-06: 不明確な表現が気になったので若干編集しました。
2006-01-06: ちょい加筆。

Jul 1, 2005

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秒)」を指定してあります。

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

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