MilkyWiki DockerPostgresToPostGIS Edit MetaEdit Search
Dockerでpostgresからpostgis/postgisに移行する方法。
基本的にはイメージ名を変えるだけでよいが、データベースがすでにある場合はST_など関数の空間が作成されないため、以下を実行する
CREATE EXTENSION postgis;
またバックアップからの復元時にもひと手間必要
以下ができればPostGISが入っている。
SELECT PostGIS_Version();
PostGISでは、点、領域、複数の領域などのデータ型が追加され、それらに対してST_関数で操作や判定ができる。
含まれているか、隣接しているか、距離はどのぐらいかなど。
ただし、すべて緯度経度ベースで行われるため、市区町村名や地名とマッピングするテーブルやカラムが必要。
このマッピングするデータ自体はe-Statから持ってくる。
https://www.e-stat.go.jp/
地図→境界データダウンロード→小地域→国勢調査→小地域(町丁・字等)(JGD2011)のShapeFile
ShapeFile形式は、shp2pgsqlというPostGIS付属ツールでテーブルに読み込みができる。
県ごとのしかないので、一つ目はテーブルを作成してあとは追記をする必要がある。
流し込み時はshp2pgsqlでCP932(ShiftJIS)を指定すること。
流し込み終わったら、空間インデックスを作成する。
CREATE INDEX idx_estat_boundaries_geom ON estat_boundaries USING gist(geom);
アプリ側で利用する地名があるテーブルにMultiPolygon型カラムを追加する(NULL許容)。
郵便番号でのマッチングはできないので、県名、市区名、町村名で突合させ、カラムに座標をコピーしていく。
同じ町名の中に複数の郵便番号がある場合もあるが、e-Statのデータには町名までしかない。
県名、市区名、町村名で同じものが2つ出てきた場合、どれか一つのみに座標情報を入れるようにする。取り出すときは、WHERE句でNULLでないかつ1件のみとする。
区単位の座標データをマージして作る必要はない。ポリゴンを大きくすればするほどパフォーマンスが下がるようなので、
インデックスを聞かせて小さいままにしておき、クエリで判定させたほうが良い。
また、その区単位のデータを用いて、シッターやそれぞれの市区町村を扱う列に座標ポリゴンを紐づけておく。(gis列を作成するなどして)
例として、現在地に最も近い5件の拠点の検索クエリの場合を考える。
拠点データには県名と市区名が入っている。その場合、SELECTで拠点テーブルからST_Distanceで現在の座標を指定し、WHERE句で県名、市区名を指定し、
ORDER BYで現在地との距離順と<->で現在地の座標を入れて指定し、
LIMIT 5で件数を制限する。
JOIN句で座標を取ってくることもできるが、かなり遅くなると思う。
正規化
郵便番号が取得されていれば、日本郵便のデータベースもしくは住所.jpなどのデータベースで市区町村までは正規化できる。その下の番地や建物名は正規化しないと座標に変換できない。(geocoding)
Google Maps等商用位置情報サービスは結果のDBへの保存不可の場合が多いので注意。
・jageocoder OSSでAPIはなく、無料だが自分で環境を整え、データベースを入れなければならない。精度は番地までで、正規化もいい感じにやってくれる。
・libpostal St.などをStreetに開いたりはしてくれるが、日本の住所の正規化が弱いらしい。
・geolonia 商用製品のためGeocodingの場合は月5000円〜かかる。Community版があるが、これはJavascriptをブラウザで実行して、Github Pagesからデータを落としてくるもので使い勝手や信頼性の部分で微妙。
→今回はFirebase functionsで@geolonia/normalize-japanese-addressesを動かしてHTTPリクエストでGeocodingできるようにする。信頼性は置いといて。
packages.jsonに追加
"dependencies": {
...
"@geolonia/normalize-japanese-addresses": "^3.1.3",
...
},
normalize()を使って正規化後の文字列と座標を取得し、JSONで返却。
ただし、ここで出てくる精度はまちまちで実際の住所と100mほどずれることもあった。
より高精度な住所が欲しい場合はe-statのデータと突き合わせる必要がありそうだが、形式が違うのでここは一筋縄では行かなそう。
Back Last Update: Fri, 24 Jul 2026 00:36:27 +0900