Sep 28, 2006

KMLをGoogle Maps上にマップする[再]

一年以上昔のことになりますが、Ogawa::Buzz: Ajaxを使ってKMLをGoogle Maps上にマップするという記事を書きました。これはGoogle Maps APIの非同期読み込み機能を使って外部KMLファイルの内容をGoogleマップ上にマップするというものでした。

それから時は流れ、Ogawa::Buzz: XML2JSONサービスを使ってFlickr Badgeを作るを書いた時点で、そうかそうかXML2JSONサービス(XML を JSON に変換するサービス - ベータ版を公開 :: Drk7jp)を使えば別に非同期読み込みを使わずとも(proxyなどを使わずとも)Javascriptだけでkml2gmapsは実現できるじゃんと気が付きました。

面倒なので長らく放置していましたがリハビリがてらやってみました。

上のURLではサンプルKMLファイルを読み込み、Google Maps APIを使ってマップ表示します。また、下のように「?url=」に続いてKMLファイルのURLを指定すればそのファイルをマップ表示します。

さらにOgawa::Buzz: georss2kml.cgi: GeoRSSをGoogle Earthにマップするスクリプトを中継に使うことで、GeoRSSをGoogle Maps上にマップすることもできます。


XML2JSONサービスに食わすKMLファイルのContent-typeはtext/xmlやapplication/xmlでないと駄目っぽいかも。.htaccessに以下のように設定してあれば問題ないようですね。

AddType application/vnd.google-earth.kml+xml kml

あと、http://as-is.net/maps/sample.kml - Google マップ で済むがね、意味ないがねっていう話は言わない約束!!!

Sep 27, 2006

Mapper Plugin 0.12公開

Mapper Pluginをtrunk上ではGoogle Maps API version 2に対応させたきり、リリースしていなかったのを思い出したので、リリースしておきます。

Mapper_Plugin - ogawa - Google Code

このプラグインは、エントリー本文に書かれた簡単な地図記法を読み取ってGoogle Maps APIを使った地図に変換してくれるものです(詳しくは上記リンクを参照)。

例えば、

[map:東京都江東区三好4-1-1]

と書いておくと、自動的に下のような地図に変換してくれます。

Ogawa::Buzz: Mapper Plugin公開にあるGoogle Maps API version 1を使った描画と比較すると、Ogawa::Buzz: Googleマップのタイル更新による差異は歴然としていますね。

Sep 26, 2006

Googleマップのタイル更新

Google Maps API Official Blog: 日本版マップタイル更新について New Map Tiles for Japan!

一瞬何が起こったのかさっぱり分からなかったが、これは素晴らしい。ひとつ階梯を登った感じ。


東京都千代田区外神田1-18-13 - Google マップ

これは地図のビットマップと衛星画像のビットマップを重ね合わせているわけだね。

また、Google Maps APIで遊んでみるかな。

TagSupplementals Plugin 0.05公開

Movable Type 3.3以降でサポートされた「タグ」に便利機能を追加・拡張するTagSupplementals Plugin(Ogawa::Buzz: TagSupplementals Plugin公開)を例によってちょびっとアップデートしました。

機能上の変更点は、MTArchiveTagsというコンテナタグを追加して、カテゴリーアーカイブや月別アーカイブなどで、当該アーカイブのエントリーのタグのみをリストできるようにした、という点です。

カテゴリーアーカイブや月別アーカイブのテンプレートで以下のように記述すると、そのアーカイブに含まれるエントリーの持つタグのみをリストしてくれます。

<ul class="archive-tags-list">
  <MTArchiveTags>
  <li><a href="<$MTTagSearchLink$>" rel="tag"><$MTTagName$></a></li>
  </MTArchiveTags>
</ul>

あとはMovable Type 3.3以降では、MT::Pluginにコンテナタグや変数タグ、グローバルフィルターを追加するためのインタフェースが追加されていた(Movable Type オブジェクト・リファレンス - MT::Plugin)のに今更気が付いたので、それを使って少し書き直してみました。

どういうことかというと、3.2以前ではコンテナタグなどを一個追加するたびに

MT::Template::Context->add_container_tag(AContainer => \&hdlr_a_container);

と書かなくてはなりませんでしたが、3.3ではMT::Pluginオブジェクトをnewするときに簡単に宣言を加えるだけで済みます。

package MyPlugin;
use base qw(MT::Plugin);
my $plugin = MyPlugin->new({
    name => 'MyPlugin',
    ...,
    template_tags => {
        ATemplate => \&hdlr_a_template,
        BTemplate => \&hdlr_b_template,
    },
    container_tags => {
 AContainer => \&hdlr_a_container,
 BContainer => \&hdlr_b_container,
    },
    global_filters => {
 AFilter => \&hdlr_a_filter,
    },
});
MT->add_plugin($plugin);

これ使うと下位互換性がなくなっちゃうわけですけどね。


他にもこんな機能があったらなという希望があったらコメント・トラックバックでお知らせください。簡単に実現できる機能から順に気まぐれに更新していきます。

TagSupplementals - ogawa - 「タグ」機能を追加・拡張するプラグイン。 - Google Code

Sep 24, 2006

明治神宮球場で野球を観る

勝手に盛り上がってきているので神宮球場に野球観戦に行ってきた。

Yahoo!プロ野球 - 2006年9月24日 ヤクルトvs.中日 結果
2006シーズン 公式戦/試合結果

実にしょっぱい試合だった。ヒットを打たれても点を取られないのが朝倉健太の持ち味なのに、狭い球場と風のために初回、2回にホームランを打たれておしまい。ただそれだけの試合。3回以降は淡々と進む典型的な負け試合。

朝倉の調子自体は悪くなかったと思った。岩村に打たれた球は高かったけど。

高校生ドラフトでは、堂上弟をお持ち帰り!!

Sep 17, 2006

PeriodicVacuum Plugin 0.01公開

定期的にデータベースのvacuum命令を実行するプラグインを作ったので公開しておきます。

PeriodicVacuum_Plugin - ogawa - 定期的にMovable TypeデータベースのVacuumを実施するプラグイン。 - Google Code

データベースでは一般に、削除したレコードが使用していた領域は、解放されずに再利用されます(なぜそうなっているかと言えば、解放操作はレコードの削除のたびに実施するには重すぎる処理で、再利用した方が大抵の場合都合が良いからです)。このため、例えば、トラックバック・コメントスパムを大量に受信した場合、それらを削除してもデータベースファイルのサイズはほとんど変化しないという現象が観測されるはずです。

このことは、特にレンタルサーバなどでSQLiteを使用している場合には問題となり得るでしょう。なぜなら、SQLiteが使用するデータベースファイルのサイズを、多くとも、賃借しているディスク容量以内に抑える必要があるからです。

一方で、データベースファイルの非使用領域の解放操作は、明示的に指示すれば、どのDBエンジンでもおおむね可能です。例えば、SQLiteやPostgresではvacuum命令、MySQLではoptimize table命令が用意されており、これらを実行すれば非使用領域の解放とインデックスの再構成が行われるようになっています。

PeriodicVacuumプラグインは、一週間に一度*1、vacuum命令を実行する機能を実現します。これにより、自動的にデータベースファイルのサイズを小さく保つことができます。

*1 正確にはエントリー、コメント、トラックバックなどを削除したタイミングで、前回のvacuum命令の実行から一週間以上経過していた場合にだけ実行されます。


このプラグインは、Movable Type 3.3で追加されたTask Manager機能の習作です。週に一度実行されるtaskを登録しておき、このtaskを実行するコールバック関数を、MT::App::CMSでMTオブジェクトを削除したときに呼び出されるフックに登録してあるだけです。類似の機能を実現したい場合にはこのプラグインのソースコードが役に立つでしょう。

定期的に実行する必要がなければ、vacuumの実行は下のような簡単なスクリプトでも実現できます。こちらならMT 3.3でなくても利用できます。

vacuum.cgi

Sep 13, 2006

タグ機能はCompare / Collate Pluginと組み合わせて使うべし、なぜにゃらば!!

なぜにゃらば、それはそうしないと使い物にならないからです。

Movable Type 3.3の標準のタグ機能でソートしたりリストの一部を取り出したりできないので困るという話は割とよく見かけます。

greenplastic.net: 未だにMT3.3へ移行できない理由

しかし、Compare PluginやCollate Pluginを使えば、そうした問題はごく簡単に解決できます。

大まかに言って、Compare Pluginはフィルター、Collate Pluginはソーター、という相補的な役割を持っています。例えば、タグやアーカイブリストのような大きなリスト構造があるとき、必要なアイテムだけを抽出するにはCompare、適当なキーに対してソートする(あるいは、ソートして最初のN件を取り出す)にはCollateを使います。Compareで抽出したリストに対してCollateでソートするということもできます。

以下では、タグ機能とCompare/Collate Pluginを組み合わせて利用する例を挙げます。

Compare Pluginを利用する例

頻度が一定以上高いタグ(ここでは、MTTagRankの値が3以下のタグ)だけをリストしたい場合には、Compare Pluginを使って以下のように書くことができます。

<h2>Major tags</h2>
<ul>
  <MTTags>
    <MTIfLessOrEqual a="[MTTagRank]" b="3" numeric="1">
      <li><a title="Tag: <$MTTagName encode_html="1"$>"
             href="<$MTBlogURL$>tag/<$MTTagName encode_url="1"$>">
        <$MTTagName encode_html="1"$>
      </a></li>
    </MTIfLessOrEqual>
  </MTTags>
</ul>

Collate Pluginを利用する例

使用頻度の高いタグを20個リストしたい場合には、Collate Pluginを使います。まず、MTCollateCollectでタグ情報を取り出しておきます。*1

<MTCollateCollect>
  <MTTags>
    <MTCollateRecord>
      <MTCollateSetField name="tag_name"><$MTTagName$></MTCollateSetField>
      <MTCollateSetField name="tag_id"><$MTTagID$></MTCollateSetField>
      <MTCollateSetField name="tag_count"><$MTTagCount$></MTCollateSetField>
      <MTCollateSetField name="tag_rank"><$MTTagRank$></MTCollateSetField>
      <MTCollateSetField name="tag_search_link"><$MTTagSearchLink$></MTCollateSetField>
    </MTCollateRecord>
  </MTTags>
</MTCollateCollect>

次にtag_countで降順にソートし、最初の20件を取り出すだけです。簡単ですね。

<h2>Tags most used</h2>
<ul>
  <MTCollateList limit="20" sort="tag_count:#:-">
    <li>
      <a title="Tag: <$MTCollateField name="tag_name" encode_html="1"$>"
        href="<$MTBlogURL$>tag/<$MTCollateField name="tag_name" encode_url="1"$>">
        <$MTCollateField name="tag_name" encode_html="1"$>
      </a>
    </li>
  </MTCollateList>
</ul>

TagSupplementals Plugin(TagSupplementals - ogawa - 「タグ」機能を追加・拡張するプラグイン。 - Google Code)を使えば、最近更新されたタグを20個リストすることもできます。

そのためにはまず、*1 のMTCollateSetFieldの列に以下を追加します。

      <MTCollateSetField name="tag_last_updated"><$MTTagLastUpdated
        format="%Y%m%d%H%M%S"$></MTCollateSetField>

次にtag_last_updatedで降順にソートし、最初の20件を取り出します。

<h2>Tags most recently updated</h2>
<ul>
  <MTCollateList limit="20" sort="tag_last_updated:#:-">
    <li>
      <a title="Tag: <$MTCollateField name="tag_name" encode_html="1"$>"
        href="<$MTBlogURL$>tag/<$MTCollateField name="tag_name" encode_url="1"$>">
        <$MTCollateField name="tag_name" encode_html="1"$>
      </a>
    </li>
  </MTCollateList>
</ul>

両方とも利用する例

かなり恣意的な例ですが、MTTagRankの値が3以下のタグを、使用頻度や更新時刻でソートして20個取り出すこともできます。

*1 の代わりに以下のように書けばよいわけです。

<MTCollateCollect>
  <MTTags>
    <MTIfLessOrEqual a="[MTTagRank]" b="3" numeric="1">
      <MTCollateRecord>
        <MTCollateSetField name="tag_name"><$MTTagName$></MTCollateSetField>
        <MTCollateSetField name="tag_id"><$MTTagID$></MTCollateSetField>
        <MTCollateSetField name="tag_count"><$MTTagCount$></MTCollateSetField>
        <MTCollateSetField name="tag_rank"><$MTTagRank$></MTCollateSetField>
        <MTCollateSetField name="tag_search_link"><$MTTagSearchLink$></MTCollateSetField>
        <MTCollateSetField name="tag_last_updated"><$MTTagLastUpdated
          format="%Y%m%d%H%M%S"$></MTCollateSetField>
      </MTCollateRecord>
    </MTIfLessOrEqual>
  </MTTags>
</MTCollateCollect>

Sep 12, 2006

TBBuiltinThrottleFix Plugin公開

MT::App::Trackback::_builtin_throttleを再定義して、(1) 同一IPアドレスからのトラックバックの個数がOneHourMaxPings, OneDayMaxPings以上になったときにスロットルする、(2) OneDayMaxPingsの検査時にThrottleSecondsを使わずに24時間以内のトラックバックの個数を数える、ように動作変更するプラグインを公開しておきます。

TBBuiltinThrottleFix_Plugin - ogawa - MT::App::Trackback::_builtin_throttleにパッチ当てするプラグイン。 - Google Code

需要があるかどうかよく分かりませんけど。

参考: Ogawa::Buzz: ThrottleSecondsとはいったい何なのか?

Sep 10, 2006

ThrottleSecondsとはいったい何なのか?

hxxk.jp - Movable Type の HTTP error: 403 Throttled に関するまとめ

よいまとめですね。Movable Typeの混乱した仕様をよく説明できています。一番の混乱の原因は、ThrottleSecondsというパラメータに"ad hocに"複数の意味を持たせ、それをそのままにしていることだと私は考えているので、このエントリーではその観点からまとめてみましょう。


ThrottleSecondsは、現在、MT::App::Comments, MT::App::Trackback, MT::App::Searchの3つの標準MTアプリケーションのThrottling機能で利用されています(プラグインから利用することもできますが省略)。以下では、各アプリケーション別にThrottleSecondsの役割と無効化の可否、そしてコメントを述べます。

MT::App::Comments

役割

ThrottleSeconds秒以内の、同一IPアドレスからのコメント投稿をスロットルします。また、(ThrottleSeconds * 10 - 1)秒以内の、同一IPアドレスからの8件以上のコメント投稿をスロットルします。

無効化の可否

ThrottleSecondsに0以下の値を設定すると、スロットリングは実施されません。

コメント

妥当な仕様に思えます。

MT::App::Trackback

役割

一時間にOneHourMaxPings個以上のトラックバック受信をスロットルします。また、(ThrottleSeconds * 4000 + 1)秒間にOneDayMaxPings個以上のトラックバック受信をスロットルします。

無効化の可否

ThrottleSecondsを0以下に設定しても、スロットリングは実施されます。

0未満の値を設定すると「未来のある時点以降に受信したトラックバックの個数がOneDayMaxPingsを超えたときにスロットルする」という意味になるので、実質的にOneDayMaxPingsによるスロットリングだけは無効化できます。また、OneHourMaxPings, OneDayMaxPingsの値を極めて大きな値にすることでも実質的に無効化できます。

どちらも「実質的に無効化」できるだけでスロットリング機能をスキップする手段がありません。

コメント

そもそもThrottleSecondsの値を使う理由がありません。悪くともThrottleSecondsとは独立の変数で制御すべきですね。

OneDayMaxPingsがその名前が規定する機能を正しく持つべきであるという観点からすれば、24時間以内のOneDayMaxPings個以上のトラックバック受信をスロットルするのが妥当な仕様です。逆に言えば、現状の仕様ではOneDayMaxPingsというディレクティブ名はユーザの誤解を招くだけです。

また、スロットリング機能をスキップする手段が用意されていないのは、コメントのスロットリングと比較すると、対称性に欠けます。

MT::App::Search

役割

(タグ検索を除く)通常検索時に、ThrottleSeconds秒以内の、同一IPアドレスからの検索をスロットルします。

スロットルに用いるアクセス履歴を記録するため、TempDirディレクティブで指定したディレクトリ(デフォルトでは/tmp)にmt-throttle.dbという名前のBerkeleyDBファイルを作ります。

無効化の可否

ThrottleSecondsを0にしてもスロットル機能は有効です。

ThrottleSecondsに0以下の値を設定すると、「実質的に」スロットルが無効になります。

コメント

無効化はできませんが仕様自体は妥当に思えます。ただし、コメント投稿のスロットリング機能と同じThrottleSecondsの値を利用する理由もありません。別のディレクティブで指定する仕様であってもよいでしょう。

また、アクセス履歴の格納場所と方法に関しては一考の余地があります。

まず、格納場所について。例えば、レンタルサーバなどでの利用を想定してみるとよいでしょう。複数のユーザが/tmpを共有しており、CGIはsuExecでユーザ権限で実行されるとします。すると、複数のユーザが同一の/tmp/mt-throttle.dbを共有することになります。しかし実際には「最初に」MT::App::Searchを使ったユーザの権限でmt-throttle.dbが作られ、他のユーザは書き込めません。このため、スロットリング機能が有効に使えないという事態が起き得ます。

根本的に格納場所についての周知が不足しています。本来は、TempDirはMovable Typeのインストールベースに対してユニークなディレクトリを指定すべきですが、そうしなかった場合のデメリットが広く知られているようには思えません。

次に格納方法についてですが、Movable TypeのDBではなくて独自のBDBファイルを使う理由が分かりません。BDBを用いた方が単純に速いという観測に基づいているのかもしれませんが、そもそもMT::App::Search自体がDBへのアクセスを必要とする低速な処理であり、履歴管理を少々軽量化できても効果は無視できる程度です。ですから、Movable TypeのDBを使ってもよいはずです。MT::Sessionのように任意のデータを一時的にストアしておく仕組みを利用すれば実装自体は容易でしょう。また、当然ですが上で述べた/tmp/mt-throttle.dbが共有されてしまう問題の抜本的な解決にもなります。

Sep 6, 2006

TagSupplementals Plugin 0.04公開

Movable Type 3.3以降でサポートされた「タグ」に便利機能を追加・拡張するTagSupplementals Plugin(Ogawa::Buzz: TagSupplementals Plugin公開)をちょびっとアップデートしました。

変更点は、MTRelatedEntriesにweightオプション(現状は"constant"と"idf"のいずれかを選べる)を追加して、エントリー間の「関連度」の計算方法を選択できるようにしたというただ一点です。

下のようにweightオプションが指定できます。

<MTEntries lastn="10">
  <h2><a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a></h2>
  <$MTEntryBody$>
  
  <ul>
    <MTRelatedEntries weight="idf" lastn="10">
      <li><a href="<$MTEntryPermalink$>"><$MTEntryTitle$></a></li>
    </MTRelatedEntries>
  </ul>
  
</MTEntries>

デフォルトではconstantになっているので、結果が気に入らないなーという場合にはidfを指定してみるとよいでしょう。ただし、処理速度はidfの方が遅くなります。一応計算に必要な情報をキャッシュしたりしているので無闇に遅いことはありませんが。


MTRelatedEntriesの「関連度」についてまとまった説明をしてこなかった(つまりはユーザにとってブラックボックス化していた)ことが気になっていたので、このエントリーの残りの部分ではその説明をしておきます。

まず、Dをエントリー集合とします。ある元d∈Dに対して、そのタグ集合をT(d)と書くことにします。このとき、あるd0∈Dに対する、各エントリーのスコア関数は典型的には、

SCORE(d0, d) = ∑t∈T(d0) tf(t, d) weight(t)

のように定式化できます。

ここで、tf(t, d)はタグtdのタグ集合T(d)に含まれていれば1、そうでなければ0を返す関数とします。一般のドキュメント空間ではT(d)は複数個のtを含むことができますが、タグ集合においてはあるタグが含まれるか含まれないかの二つの状態しかないので、このような単純なステップ関数として定義するのが妥当です。

次にtに関する重み付け関数weightには、安直にはconstantidfが定義できるでしょう。constant(t)tの値に関わらず定数を返す定数関数

constant(t) = 1 … (1)

であり、idf(t)tの出現回数freq(t)の逆数関数で、例えば、

idf(t) = 1 / (freq(t) - 1) … (2)

のように定義できます。idf(t)の定義にはいくらでもバリエーションが作れて、

idf(t) = log(N(D) / freq(t)) + 1

と定義する流儀もあります(このとき、N(D)はエントリー集合の大きさを表します)。

constantの場合、tの重み付けを考慮しませんから、スコア関数は単にd0と共通に使われているタグの個数を返します。これに対してidfでは、使用頻度の低いものほど重要なタグと看做して重み付けをしてスコア付けをします。タグを基にした検索でどちらがより望ましい結果を示すのかは私には判断できませんが、一般の文書検索では後者のような重み付け手法をを発展させた方法を採っています。

weightにどのようなものを使うかはさておき、こうして対象エントリーd0に対するスコアSCORE(d0, d)をすべて計算することができます。そしてそのスコアの大きいものから順にリストしてやれば、d0により類似したエントリーを抽出することができます。

MTRelatedEntriesはざっとこのようなロジックで動作しています。もし望ましい結果が得られないのであれば、weightを変更することでより良い結果が得られる可能性があります。

(あー面倒くさかった。あとでMathMLで書き直すかも。)


他にもこんな機能があったらなという希望があったらコメント・トラックバックでお知らせください。簡単に実現できる機能から順に気まぐれに更新していきます。

TagSupplementals - ogawa - 「タグ」機能を追加・拡張するプラグイン。 - Google Code

About Me

My Photo

つくばで働く研究者

Total Pageviews

Amazon

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