WalkDBまとめ

WalkDB

このところ時間の編目をかいくぐりながら寝る時間を削って、WalkDBの改修をしていたのだった。WalkDBというのは1997年以降のぼくの全散歩の経路を記録し、検索するシステムだ。ようやく一段落ついたといっていいと思うが、それを公開するあてはいまのところないし、公開しても意味のないものだと思うので、代わりに技術的ノウハウをまとめておこう。

今回の改修のテーマは二つ。

  • フレームワークとしてstrutsを使う。
  • PostgreSQLで地理データを扱うための拡張PostGISを利用。

strutsを使うことで、WWWアプリケーションのお定まりの処理はフレームワーク側に任せることができた。単純にコード量が減ったわけではないが、ある程度手順に従って実装できるのがうれしい。気がついたことをいくつか。

  • validatorを使ってサーバ側で入力チェックを行う場合は、データの自動的な型変換を行わず、すべてStringで受けたほうがいい。validateの前に型変換が行われるので、意味がないのだ。
  • FormFileでファイル名やファイル以外のデータの文字コードを指定する場合は Filterを使って、request#setCharacterEncoding(String enc)を呼び出す。
  • checkboxの初期状態をonにするのは難しい。offだと値が送られず状態が変化しないので、Formのresetメソッドの中でoffにしている。そのせいで初期値は必ずoffになってしまう。
  • validatorのvalid-when(条件付きvalidate)機能を使うにはantlr.jarが必要。

次にPostGISについて。

従来は点の集合で管理していたので、ある場所からある半径以内を通過した散歩を求める場合、たまたま点がその中に入っていればいいが、そうでなければ検索にひっかからない可能性があった。PostGISではちゃんとLINESTRINGつまり線分のつながりとして管理されているので、正確に求まるようになった。あわせて、ある散歩と交差する散歩を探す機能を追加した。

PostGISのオブジェクトはすべてSRIDというパラメータをもち、それによってどの座標系で記述されているかという情報を示している。通常地理データは球面(正確には回転楕円体)上の緯度経度で持つことが多いが、それでは扱いづらいので、それを平面上に投影して単位をメートル等一般的なものにした座標系を並行して用いる。DBでは位置を緯度経度で保持しつつ、クエリーの際にそれをtransform関数で平面に投影するのが何かと都合がいい。今回はDB上はGCS<em>TOKYO(SRID:4301)でデータを保持し、それをSQLの中で都度、長野県南牧村を中心として平面に投影した座標系Japan</em>Zone_8(SRID:30168)に変換して、距離や交差の判定を行っている。

PostGISには空間インデックスという機能があって、位置検索の際効果を発揮する。

CREATE INDEX path_index
  ON walkinfo
  USING gist
  (transform(path, 30168));

USING gistと指定すると空間インデックスになる。この例では、平面上に投影したデータに対してインデックスをはっている。

空間インデックスは複雑な演算に対しては働かず、二つのデータをそれぞれ過不足なく囲む矩形同士がオーバーラップするかどうかという単純な演算(&&演算子)に対して有効になる。selectの条件を記述する際には、まず&&で絞り込んでから、本来の条件で検索すると効率的だ。

<td>
  375ms
</td>
<td>
  485ms
</td>
<td>
  188ms
</td>
ある点から半径3km以内の散歩を検索
ふつうに検索
&&で絞り込んでから検索(空間インデックスなし)
&&で絞り込んでから検索(空間インデックスあり)

今回PostgreSQLもPostGISもWindows版を利用した。入手先は以下の通り。