Sequel を介した PostGIS からのデータ読み出しの基本的なコード

Sequel を介した PostGIS からのデータ読み出しの基本的なコードを入門者向きにまとめました。
かなりはしょっている感じになりますが、まずは最小限の説明をしてみます。

コード

これまでの方法で PostGIS に移した基盤地図情報(道路縁)について、

  • その長さが 30 秒以上のレコードを取り出し
  • それぞれについて、その幾何情報と「種別」属性を取り出す

という作業をやりたいとします、そのコードは次のとおりになります。

# coding: cp932
require 'rubygems'
require 'sequel'

DB = Sequel::connect('postgres://fitter:happier@localhost/more_productive',
  {:encoding => 'SJIS'})

DB[:hatena_rdedg].filter(:ST_Length.sql_function(:the_geom) > 30.0 / 3600).
  select(:ST_AsText.sql_function(:the_geom), :"種別").each {|r|
  print "#{r[:"種別"]} #{r[:st_astext]}\n"
}

DB.disconnect

このコードを出来るだけ詳しく説明します。

  • Ruby の定数 DB には、いつもの PostGIS への接続を入れています。接続を開始するときには Sequel::connect を使い、接続を終了するときには、disconnect を使います。
  • DB[:hatena_rdedg] は、接続したデータベースの中の、 hatena_rdedg という名前のテーブルを表します。:hatena_rdedg のように、文字列の前に : を付ける表現は、 Ruby のシンボルという情報表現です(資料:プログラミング言語 Ruby リファレンスマニュアル)。
  • filter は Sequel のメソッドで、() 内の条件でテーブルの中のデータを絞り込むという意味です。
  • :ST_Length.sql_function(:the_geom) は、SQL 関数 ST_Length を、PostGIS のカラム the_geom に適用するという意味です。ここで、ST_Length は PostGIS の関数です。PostGIS については、PostGIS 1.5.1 マニュアル 日本語訳 に良い日本語訳が公開されているので、こちらを参考にするとよいと思います。the_geom は d:id:hfu:20100519スクリプトで決めたものですが、幾何情報のカラム名を the_geom にするのはちょっとした「お約束」になっていますので、ふつうは幾何情報は the_geom というカラムに入れます。
  • 30.0 / 3600 は、30秒を十進経緯度に直す処理です。
  • :ST_Length.sql_function(:the_geom) > 30.0 / 3600 で、「the_geom の長さが 30 秒より大きい」という意味になります。
  • DB[:hatena_rdedg].filter(:ST_Length.sql_function(:the_geom) > 30.0 / 3600) は、「テーブル hatena_rdedg から、the_geom の長さが 30秒以上のものを選択する」という意味になります。
  • select は Sequel のメソッドで、PostgreSQL (PostGIS) から何を選び出すかを設定する役割を持ちます。
  • :ST_AsText.sql_function(:the_geom) は、カラム the_geom に ST_AsText という SQL 関数を適用したもの、という意味になります。ST_AsText は PostGIS の関数で、その仕様はPostGIS 1.5.1 マニュアル 日本語訳 に解説されています。
  • :"種別" は、カラム 種別 を指します。ここで、"" を使ったのは Ruby の約束事で、普通 Ruby のシンボルを作るには文字列の前に : を付ければよいのですが、日本語文字列をシンボルにするには、日本語文字列を "" などで括ってから : を付けるのがよいのです。
  • select(:ST_AsText.sql_function(:the_geom), :"種別") で、the_geom に ST_AsText を適用したものと、「種別」を選択する、という意味になります。
  • each は、Sequel で定義されたメソッドで、これまでに選択した PostGIS のデータを、行ごとに each 以下のブロックに渡してくれます。each は Sequel に限らず Ruby で一般的に用いられる繰り返し処理の方法です。
  • DB[:hatena_rdedg].filter(:ST_Length.sql_function(:the_geom) > 30.0 / 3600).select(:ST_AsText.sql_function(:the_geom), :"種別").each {|r| } で、テーブル hatena_rdedg から、長さが 30秒以上のものについてその幾何情報のテキスト表現と属性「種別」を取り出し、それぞれについて r に入れて繰り返せ という意味になります。
  • 取り出した結果 r は、Ruby の Hash として渡されます。r[:"種別"] とすることで、属性「種別」を取り出すことができます。
  • select で SQL 関数を用いた場合、関数名(PostgreSQL の都合で、すべてを小文字にしたもの)が Hash のキーとなります。r[:st_astext] によって、:ST_AsText.sql_function(:the_geom) の結果を取ることが出来ます。

次回以降について

ここまでの Ruby の知識があれば、あとは PostGIS の関数リファレンスをうまく駆使すれば、かなり多くの処理(例えば、点と線分との距離)が出来るようになります。しかし、PostGIS の関数ができる処理を超えた、より細かな幾何処理(例えば、点から線分への垂線の足)は、PostGIS だけでは処理できません。そこで、GeoRuby を介して PostGIS の結果を JTS に読ませ、JTS の機能を使って細かな幾何処理を行うことが必要になってきます。これについて、あとで書きます。