緯度経度から大まかな住所を取得するために,簡易的なリバースジオコーダをSQLiteで作った話.
SQLiteで簡易リバースジオコーダ拙作のアプリ 山旅ロガーGOLD で,測定結果の大まかな住所を表示するという機能を実装するために, 簡易的なリバースジオコーダを制作したときの話です.方式正確にやるなら,行政区画のポリゴンを用意して,その内側か外側かを判定するのだと思いますが, それは大変なので,一番近い市区町村を採用するという簡易的な方法を使います.# ですので,結果は正確ではありません.「大まかな住所」という前提です 市区町村の緯度経度のデータは,国土交通省の, 位置参照情報ダウンロードサービス からダウンロードしたものを使います. 検索するためのツールですが,MySQLやPostgreSQLなどでやっても良いのですが, 対象が固定の読み取り専用データなので,SQLiteで済ませることにしました. この方が,運用管理が不要なので楽でもありますし. SQLiteのテーブル定義cities.sqlite3というファイルを作ることにします.sqlite3コマンドsqlite3 cities.sqlite3
データの準備位置参照情報ダウンロードサービス から,都道府県単位で全ての都道府県のデータをダウンロードします.47個のzipファイルをダウンロードすることになりますが,それを全て展開して, 中に入っているファイルのうち,CSVファイルだけを使います. 北海道(2014年版)は「01_2014.csv」で,これが47都道府県で47番まであります. CSVファイルの中身は,次のような感じです.
"都道府県名","市区町村名","大字・町丁目名","街区符号・地番","座標系番号","X座標","Y座標","緯度","経度","住居表示フラグ","代表フラグ","更新前履歴フラグ","更新後履歴フラグ" 今回は都道府県名(カラム0),市区町村名(カラム1),緯度(カラム7),経度(カラム8)を使います. SQLiteで読ませるCSVを作るために,
という前処理を行いますが,今回は以下のようなperlのプログラムを作りました. conv.pl
perl conv.pl 01 >>all.csv perl conv.pl 02 >>all.csv ・・・ perl conv.pl 47 >>all.csv データのロードsqlite3コマンドで起動して,sqlite3 cities.sqlite3 .mode csv .import all.csv cities select count(*) from cities; 3717036
※注意 DBのサイズ的にSJISのままが良いと思いますが,取得後に必要に応じてUTF-8に変換するなどの考慮が必要です. インデックスの作成緯度経度で検索するので,緯度経度にインデックスを作成します.sqlite3 cities.sqlite3 create index cities_i1 on cities (lat, lon); ・検索したときの実行計画を確認 explain query plan 検索の実行検索したい位置の緯度経度が(34.788395, 135.234160)の場合,基本はこうですが,
そのため自分は,これを少しずつ大きくして検索を繰り返し,ヒットした時点で打ち切るようにしています.
具体的には, ちなみに最初から大きい値で検索してしまうと,インデックスで絞りきれないため,遅くなります. 余談元々の目的が,Androidアプリで緯度経度から住所を取得するという話なら, Android標準のリバースジオコーダを使えば良いのでは?と思われるかも知れませんが, このあたりをご覧ください. 実際自分の手元にも,リバースジオコーダが動作しない端末があります orz |