y-matsui::weblog

電子楽器、音楽、コンピュータ、プログラミング、雑感。面倒くさいオヤジの独り言

緯度経度に対する円範囲指定検索で

GPSで取得した緯度経度をキーに、円範囲を指定して、近傍検索を行うための調査をしている。
データベース上の位置情報を効率的に検索する方法(PostgreSQL編)に書かれている、Postgresデータベースの幾何データ型を使って検索する手順を確認していたところ、「はて、1秒は何メートルなんだっけか」と調べていて、ここギコ GoogleMapsと連動したいなら幾何データ型よりPostGISにぶち当たった。
上記エントリーにリンクされているここを見ると、日本がほぼ収まる”緯度25-45度の範囲で”、経度1秒あたり最大で6メートルの差があることが分かる。緯度方向の1秒がわずか10センチの差しかないことからすれば、経度方向の1秒の誤差6メートルは確かに大きい。
つまり、プラスマイナス1秒の単位でクエリーを書いたとして、緯度方向はほぼ30.8メートル、経度方向は22-28メートルの開きがあるということだ。
ううん、100メートル相当の円で検索したいとして±3秒の範囲指定検索を実行したときに、緯度方向は93メートルだけど、経度方向は66メートルにしかなっていないとすると確かに、「あんた、何を検索してんの?」ってなもんですねぇ。この差が問題にならない用途なら、割り切ってやっちゃえばいいんだろうね。
ただ、最大で30メートルの誤差がありますと記載するか、検索にヒットしない場合は範囲を広げて検索してください・・みたいに利用者に周知しないと問題かな。
PostGISか。ちょっと調べよう。

MySQLで指定した緯度経度から半径nメートル内検索っぽいのを実現するSQLに書かれている
DBに入ってるのは度単位なので、1秒を度単位に変換すると約0.000277778なので、300m離れると0.00277778度変わるはず。
上野駅の緯度が35.713768度、経度が139.777254度なのでそれぞれプラスマイナス0.00277778度すると300mくらい離れた地点の緯度経度が計算できる。

に従って、Postgres上でselect * from tbl_point where latlon @ circle(point(35.713768,136.777254),0.00027777)みたいなクエリを発行すると、それなりの結果が返ってきた。
この結果を採用したいなぁ。楽だし。

■疑問
「緯度経度によって、1秒に相当する長さが違う」と言う問題と
「楕円空間上を緯度経度の範囲で検索する」という問題は、そもそも別なのではないか?
緯度経度で表現する円の範囲で、含まれる緯度経度のポイントを検索する際に、1秒の長さの違いは無関係なのでは?と、思い立った次第。
それを、「100メートルの円に含まれる地物を検索します」と表現してしまえば間違いなのだろうが・・。
違うのか?

■元に戻ってPostgreSQLの幾何データ検索のテスト結果
愛知県の街区レベル位置参照情報データ153万ポイントを、根性で登録して、
create index idx_point on tbl_address using gist(circle(p_latlon,0));
と半径ゼロを指定したcircle関数の結果(点)をインデックス化。←158427ms

select * from tbl_address where circle(p_latlon,0) @ circle(point(35.********,136.********),0.0009);

こんなクエリーを投げると、153万件を検索してもわずかに10-40ms
これが、インデックスを張る前の全舐め
select * from tbl_address where p_latlon @ circle(point(35.********,136.********),0.0009)
の場合は4236ms

100-400倍以上の高速化。

よっしゃ、GPS携帯からクエリしよう。