PostGIS をやらないといけなさそうで、Docker 使って触ってみました
PostGIS を使うと、空間データが SQL で扱えるようになります
詳しくは PostGIS のリンクなどを参照
PostGIS だと空間データ用の関数が増え、
SELECT ST_Contains('POLYGON((0 0, 1 0, 1 1, 0 0))'::GEOMETRY,'LINESTRING(0 0, 1 0, 1 1, 0 0)'::GEOMETRY);
だと、POLYGON(多角形)と LINESTRING(直線、折れ線)が ST_Contains で交わっているかどうか、が SQL で確認できます
結果は t (true) / f (false) で文字で返ってきます
POLYGON だとかは、ジオメトリタイプ一覧をながめる を参考にしました
mdillon/postgis - Docker Hub のイメージを使いました
pull して sql を用意
docker pull mdillon/postgis
mkdir init
echo 'CREATE EXTENSION postgis;' > init/init.sql
docker run でオプション付けていってもいいですが、docker-compose.yml を用意しておくと便利
version: '3'
services:
db:
container_name: postgis_container
image: mdillon/postgis
environment:
POSTGRES_DB: sampledb
POSTGRES_USER: pguser
POSTGRES_PASSWORD: password
volumes:
- ./pgdata:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d
これで
$ docker-compose up -d
で立ち上がります
動作確認してみます
$ docker exec -it postgis_container psql -U pguser sampledb
で、Docker 内の PostgreSQL につないで、SQL を流す
$ SELECT ST_Contains('POLYGON((0 0, 1 0, 1 1, 0 0))'::GEOMETRY,'LINESTRING(0 0, 1 0, 1 1, 0 0)'::GEOMETRY);
st_contains
-------------
f
(1 row)
と動作してそうです
ちなみにこのときの PostgreSQL のバージョンは
$ psql --version
psql (PostgreSQL) 11.2 (Debian 11.2-1.pgdg90+1)
PostGIS には Shapefile を取り込む shp2pgsql というツールがついているので取り込んでみます
shp2pgsql の使い方は
$ shp2pgsql -W (Shapefileの文字コード) -D -I -s 4612 (Shapefile名) (データベースの保存したいテーブル名)) > import.sql
-D -> dump形式でinsert形式にしない
-I -> 空間インデックスを貼る
-s 4612 -> 空間参照系のコード SRID を 4612 (JGD2000地理座標系) と指定
といったコマンドで、sql ファイルに吐き出せます
空間参照系 4612 は、PostGIS でよく使う SRID まとめ : してログ - LANDHERE を参考にしました
さらに
-p -> スキーマだけ
-a -> データだけ
を付けられます
Shapefile は 統計 GIS データダウンロード | 政府統計の総合窓口 から大阪府をダウンロードしてきました
解凍するとファイルが 4 つあるので、Docker container から見える init ディレクトリに置いて、Docker container 内で実行します
$ docker exec -it postgis_container
$ cd docker-entrypoint-initdb.d
$ shp2pgsql -W cp932 -D -I -s 4612 h27ka27.shp sample_table > h27ka27.sql
これで SQL ファイルができたので、PostgreSQL に入れてみます
$ psql -U pguser sampledb -f h27ka27.sql
これでテーブルができました
\d sample_table;
Table "public.sample_table"
Column | Type | Collation | Nullable | Default
------------+-----------------------------+-----------+----------+--------------------------------------------------------
gid | integer | | not null | nextval('sample_table'::regclass)
key_code | character varying(11) | | |
pref | character varying(2) | | |
city | character varying(3) | | |
s_area | character varying(6) | | |
pref_name | character varying(12) | | |
city_name | character varying(14) | | |
s_name | character varying(96) | | |
kigo_e | character varying(3) | | |
hcode | smallint | | |
area | numeric | | |
perimeter | numeric | | |
h27kaxx_ | integer | | |
h27kaxx_id | integer | | |
ken | character varying(2) | | |
ken_name | character varying(12) | | |
sityo_name | character varying(22) | | |
gst_name | character varying(14) | | |
css_name | character varying(14) | | |
kihon1 | character varying(4) | | |
dummy1 | character varying(1) | | |
kihon2 | character varying(2) | | |
keycode1 | character varying(9) | | |
keycode2 | character varying(9) | | |
area_max_f | character varying(1) | | |
kigo_d | character varying(2) | | |
n_ken | character varying(2) | | |
n_city | character varying(3) | | |
kigo_i | character varying(1) | | |
moji | character varying(96) | | |
kbsum | smallint | | |
jinko | bigint | | |
setai | bigint | | |
x_code | numeric | | |
y_code | numeric | | |
kcode1 | character varying(7) | | |
geom | geometry(MultiPolygon,4612) | | |
Indexes:
"sample_table_pkey" PRIMARY KEY, btree (gid)
"sample_table_geom_idx" gist (geom)
データ数は
select count(*) from sample_table;
count
-------
8897
(1 row)
sample_table の geom カラムに MultiPolygon データが入っているのである緯度経度を含む丁目を調べてみると
select gid, key_code, pref, city, s_area, pref_name, city_name, s_name from sample_table where ST_Intersects(ST_GeomFromText('POINT(135.4810096 34.677329)', 4612), geom::geometry) <> 'f';
gid | key_code | pref | city | s_area | pref_name | city_name | s_name
-----+-------------+------+------+--------+-----------+-----------+--------------
188 | 27106012001 | 27 | 106 | 012001 | 大阪府 | 西区 | 千代崎1丁目
(1 row)
こんな感じで取れました
POINT の指定は、ST_GeomFromText をかまして SRID を同じものを指定してあげないと動作しませんでした
プログラムを書いて判定するのは大変そうですが、これだと高速で動くのでよさそうです