Docker と PostGIS で札幌駅から中島公園までの距離を空間関係関数で計算してみた

Docker と PostGIS で札幌駅から中島公園までの距離を空間関係関数で計算してみた

2026.02.28

はじめに

業務で GIS の知識が必要になりました。まずはローカル環境で手を動かし、空間データベースの基礎を身につけるところから始めます。

Docker で PostGIS 環境を構築し、札幌のランドマークを題材に拠点間の距離を計算してみました。札幌駅や大通公園の緯度経度をデータベースに投入し、空間関係関数で距離を求めるまでをひととおり試した内容をまとめます。

結果早見

Docker Compose で PostGIS 環境を構築し、札幌のランドマーク 6 地点の緯度経度を登録しました。ST_DistanceSphere 関数で大通公園から各地点への距離を計算し、Google Maps の直線距離とほぼ一致することを確認できました。

  • Docker で postgis/postgis イメージを使えば PostGIS 環境を一瞬で構築できる
  • ST_MakePoint で緯度経度を登録し、ST_DistanceSphere で距離をメートル単位で取得できる
  • 計算結果は Google Maps の経路計算とほぼ一致し、答え合わせが簡単にできた

Docker Compose で PostGIS 環境を構築する

構成概要

今回は Apple Silicon(M4, arm64)の MacBook Air を使用しています。公式の postgis/postgis Docker イメージは amd64 向けに提供されています。そのため docker-compose.ymlplatform: linux/amd64 を指定し、Rosetta 2 経由で動作させています。

コンポーネント バージョン 用途
PostgreSQL 16(LTS) リレーショナルDB
PostGIS 3.5 PostgreSQLの空間拡張

ファイル構成

learn-gis/
├── Dockerfile
├── docker-compose.yml
└── sql/
    └── 00_init.sql          # PostGIS拡張有効化(自動実行)

Dockerfile

公式の postgis/postgis イメージを使えば、PostgreSQL + PostGIS がセットで手に入ります。現時点で安定版の組み合わせにしました。

FROM postgis/postgis:16-3.5

docker-entrypoint-initdb.d/ に初期化 SQL を置くと、コンテナ初回起動時に自動実行されます。この仕組みを使って PostGIS 拡張を有効化します。

docker-compose.yml

services:
  db:
    build: .
    platform: linux/amd64
    container_name: postgis-handson
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: gisuser
      POSTGRES_PASSWORD: gispass
      POSTGRES_DB: gis_db
    volumes:
      - postgis_data:/var/lib/postgresql/data
      - ./sql/00_init.sql:/docker-entrypoint-initdb.d/00_init.sql

volumes:
  postgis_data:
ボリューム 用途
postgis_data DBの永続化
./sql/00_init.sql:... PostGIS拡張有効化の初期化SQL

初期化 SQL

00_init.sql
CREATE EXTENSION IF NOT EXISTS postgis;
SELECT PostGIS_Full_Version();

起動と接続確認

# コンテナのビルドと起動
docker compose up -d

# psqlで接続
docker compose exec db psql -U gisuser -d gis_db

接続できたら、PostGIS のバージョンを確認します。

SELECT PostGIS_Full_Version();

以下のような出力が返れば成功です。

POSTGIS="3.5.2 ..." [EXTENSION] PGSQL="160" GEOS="3.9.0-CAPI-1.16.2" PROJ="7.2.1 ..." ...

ポイントテーブルの作成

GEOMETRY 型とは

PostGIS では通常のテーブルに GEOMETRY 型のカラムを追加することで、空間データを格納できます。

CREATE TABLE landmarks (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    category TEXT,
    geom GEOMETRY(Point, 4326)  -- ← 空間カラム
);

GEOMETRY(Point, 4326) の意味は以下の通りです。

要素 説明
GEOMETRY PostGISの空間データ型
Point ジオメトリの種類(Point, LineString, Polygon等)
4326 SRID = EPSG:4326(WGS84、GPS座標系)

テーブル作成

psql に接続した状態で以下を実行します。

CREATE TABLE landmarks (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    category TEXT,
    geom GEOMETRY(Point, 4326)
);

geometry_columns ビューでメタデータ確認

PostGIS は空間カラムの情報を geometry_columns ビューに自動登録します。

SELECT
    f_table_name   AS table_name,
    f_geometry_column AS geom_column,
    srid,
    type
FROM geometry_columns
WHERE f_table_schema = 'public';
  table_name | geom_column | srid | type
------------+-------------+------+-------
 landmarks  | geom        | 4326 | POINT

札幌のランドマークデータを投入する

ST_MakePoint でポイントを作成

地図上の地点を緯度・経度で表した座標をポイントといいます。ST_MakePointST_SetSRID を組み合わせて、緯度経度からポイントデータを作成します。

INSERT INTO landmarks (name, category, geom) VALUES
    ('札幌駅', '駅',
     ST_SetSRID(ST_MakePoint(141.3507, 43.0687), 4326));
--                           ↑ 経度    ↑ 緯度    ↑ SRID

緯度経度は Google Maps から確認しました。

中島公園駅_-_Google_マップ_🔊.png

データ投入

札幌駅から南にある目ぼしいものの座標を調べたので投入します。

INSERT INTO landmarks (name, category, geom) VALUES
    ('札幌駅',           '駅',     ST_SetSRID(ST_MakePoint(141.3507, 43.0687), 4326)),
    ('札幌時計台',       '観光',   ST_SetSRID(ST_MakePoint(141.3536, 43.0625), 4326)),
    ('さっぽろテレビ塔', '観光',   ST_SetSRID(ST_MakePoint(141.3568, 43.0611), 4326)),
    ('大通公園',         '公園',   ST_SetSRID(ST_MakePoint(141.3563, 43.0603), 4326)),
    ('すすきの交差点',   '繁華街', ST_SetSRID(ST_MakePoint(141.3533, 43.0555), 4326)),
    ('中島公園',         '公園',   ST_SetSRID(ST_MakePoint(141.3549, 43.0487), 4326));

データ確認

投入したデータを確認します。ST_AsText でジオメトリを WKT(Well-Known Text)形式で表示できます。

SELECT name, category, ST_AsText(geom) AS wkt FROM landmarks;
        name       | category |           wkt
------------------+----------+-------------------------
 札幌駅           | 駅       | POINT(141.3507 43.0687)
 札幌時計台       | 観光     | POINT(141.3536 43.0625)
 さっぽろテレビ塔 | 観光     | POINT(141.3568 43.0611)
 大通公園         | 公園     | POINT(141.3563 43.0603)
 すすきの交差点   | 繁華街   | POINT(141.3533 43.0555)
 中島公園         | 公園     | POINT(141.3549 43.0487)

POINT(経度 緯度) の形式で格納されていることがわかります。

ポイント間の距離を計測する

ST_DistanceSphere で 2 点間の距離を計算

ST_DistanceSphere は、地球を球体として近似し、2 点間の距離をメートル単位で返す関数です。

SELECT
    a.name AS from_point,
    b.name AS to_point,
    ROUND(ST_DistanceSphere(a.geom, b.geom)::numeric, 0) AS distance_m
FROM landmarks a, landmarks b
WHERE a.name = '札幌駅' AND b.name = '中島公園';
 from_point | to_point | distance_m
------------+----------+------------
 札幌駅     | 中島公園 |       2250

札幌駅から中島公園まで約 2.2km であることがわかります。この値は Google Maps で同じ 2 点間の直線距離を測定した結果とほぼ一致します。

中島公園駅_から_札幌駅_-_Google_マップ_🔊.png

大通公園から全ランドマークの距離一覧

大通公園を起点に、すべてのランドマークまでの距離を近い順に表示します。

SELECT
    b.name,
    b.category,
    ROUND(ST_DistanceSphere(a.geom, b.geom)::numeric, 0) AS distance_m
FROM landmarks a, landmarks b
WHERE a.name = '大通公園'
  AND a.name != b.name
ORDER BY distance_m;
        name       | category | distance_m
------------------+----------+------------
 さっぽろテレビ塔 | 観光     |         98
 札幌時計台       | 観光     |        329
 すすきの交差点   | 繁華街   |        587
 札幌駅           | 駅       |       1039
 中島公園         | 公園     |       1295

大通公園からもっとも遠い中島公園でも約 1.3km です。大通公園を歩いたあとに中島公園散策も十分可能ですので、ぜひ足を延ばしてみてください。

おわりに

PostGIS を使った空間データベースの第一歩として、ポイントデータの登録と距離計算を試しました。普段の SQL の延長で空間的な問いに答えられる点は、RDB を扱っているエンジニアにとって親しみやすいと感じました。

座標や、空間関係関数の計算結果を Google Maps で確認できるのは、初学者には大変ありがたかったです。座標の取得はもちろん、計算が正しいかどうかを直感的に確認できるのは助かった。ただ、札幌駅から直線で結べるところにある中島公園であったからではあるが。

今回は ST_DistanceSphere(球体近似)を使いましたが、より高精度な ST_DistanceSpheroid(楕円体計算)や、ラインやポリゴンを扱った空間クエリもあります。次のステップでは LineString(線)や Polygon(面)を使った空間検索に挑戦してみたいです。

参考

この記事をシェアする

FacebookHatena blogX

関連記事