2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PostGISに触れた備忘録

2
Last updated at Posted at 2026-08-09

初めて地理空間データを扱うシステムを作ることになり、色々と調べていたところ見つけたのがPostGISでした。この記事では、PostGISの導入や使い方を備忘録として残しつつ、実際にDocker上でPostGISを動かしてみるところまで実施してみます。

PostGISとは

PostgreSQL + GISなので、PostgreSQLに地理空間データ型と空間演算を追加する拡張機能です。地理空間データとは、地球上の実際の位置とリンクするデータのこと。GISとは、Geographic Information Systemの略で、地理空間情報を管理・加工・表示・分析する仕組み・技術のことを指します。

データベース上で地理空間データを扱えるようになります。

Docker上で動かしてみる

環境

  • Apple Silicon Mac
  • macOS Tahoe 26

今回は、postgis/postgisのDocker Imageが手元の環境では利用できなかったため、postgres:17.5-bullseyeのDocker Image上にPostGIS環境を構築します。

まずは、適当なディレクトリに下記構成のファイルを準備します。

構成

.
├── Dockerfile
├── docker-compose.yml
└── initdb
    └── 01-enable-postgis.sql
Dockerfile
FROM postgres:17.5-bullseye

# PostGIS拡張を追加する
# shp2pgsql はPostGISパッケージに含まれる
# ogr2ogr はGDALパッケージ(gdal-bin)で追加する
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
      ca-certificates \
      postgresql-17-postgis-3 \
      postgresql-17-postgis-3-scripts \
      gdal-bin \
    && rm -rf /var/lib/apt/lists/*
docker-compose.yml
services:
  postgis:
    # 同じディレクトリにある Dockerfile から独自イメージをビルドする
    # ベースは postgres:17.5-bullseye、そこへPostGISを追加したもの
    build:
      context: .
      dockerfile: Dockerfile

    # ビルド済みイメージに付けるローカル用の名前
    image: oita-postgis:17.5

    # コンテナ名を固定する(docker compose exec などで指定しやすくなる)
    container_name: oita-postgis

    environment:
      # 初回起動時に作成するデータベース名
      POSTGRES_DB: gis_db

      # PostgreSQLの接続ユーザー名
      POSTGRES_USER: gis_user

      # PostgreSQLの接続パスワード
      # 記事用の値。本番では .env ファイルなどで管理すること
      POSTGRES_PASSWORD: change_me

    ports:
      # ホスト側の5432番ポートから、コンテナ内PostgreSQLの5432番へ接続する
      # DBeaverでは localhost:5432 を指定する
      - "5432:5432"

    volumes:
      # DBデータを名前付きボリュームへ永続化する
      # コンテナを作り直しても、通常はデータが消えない
      - postgis_data:/var/lib/postgresql/data

      # 初回DB作成時に実行する初期化SQLを読み取り専用で渡す
      # 例: initdb/01-enable-postgis.sql で CREATE EXTENSION postgis; を実行する
      - ./initdb:/docker-entrypoint-initdb.d:ro


      # GeoJSONの置き場をコンテナへ読み取り専用で渡す
      # 起動時にデータを自動投入するものではない
      - ./data:/data:ro

volumes:
  # PostgreSQLのデータを保持する名前付きボリューム
  postgis_data:
01-enable-postgis.sql
-- 初回DB作成時にだけ実行される初期化SQL
CREATE EXTENSION IF NOT EXISTS postgis;

SELECT
  PostGIS_Full_Version();

initdbフォルダに格納されたsqlファイルは初回起動時データディレクトリが空の場合に実行されます。
01-enable-postgis.sqlファイルに記載のコマンドは、PostgreSQLにPostGISを追加して反映を確認するコマンドです。

実行

ターミナルを開いて作業ディレクトリに移動後、下記のコマンドを叩くことで実行できます。

docker compose up -d

動きが遅いなと感じる場合は、動作環境の命令セットアーキテクチャに対応してないDocker Imageを使っている可能性があります。特に、Apple Silicon版 Macを使用する場合は要確認です。

DBeaverで接続する

docker-compose.ymlに記載した設定情報を確認してDBeaverから接続します。

接続設定

  1. DBeaverを開いたら、画面左上のコンセントマーク(New Database Connection)をクリックします

    スクリーンショット 2026-08-05 11.58.16.png

  2. ウィンドウが開いたらPostgreSQLを選択します

    スクリーンショット 2026-08-05 12.00.49.png

  3. 接続情報を入力する

    スクリーンショット 2026-08-05 13.08.54.png

    接続情報を入力後、左下のTest Connectionボタンをクリックし接続を確認してください。確認できたらOKをクリックし設定は完了です。

  4. DBeaverのConnectionsタブを確認すると、下画像のように作成したDBが表示されているはずです

    スクリーンショット 2026-08-05 11.46.48.png

    初期状態では、spatial_ref_sysテーブルが作られています。このテーブルは、地理空間データベースで利用するSRIDと空間参照系の定義を保持するテーブルです。

PostGISの操作

データの登録

今のままでは何のデータも入っていない状態なので、オープンデータからGeojsonやShapefileを取ってきます。今回は、国土数値情報(医療機関)-大分県を使用します。

出典:国土交通省国土数値情報ダウンロードサイト(https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-P04-2020.html)

作業ディレクトリにdataフォルダを作成し、その中にダウンロードしたデータを格納します。

そして、次のコマンドで格納したGeoJSONファイルを読み込みます。

docker compose exec \
  -e PGPASSWORD=change_me \
  postgis \
  ogr2ogr \
  -f PostgreSQL \
  "PG:host=127.0.0.1 port=5432 dbname=gis_db user=gis_user" \
  /data/P04-20_44.geojson \
  -nln public.medical_facilities \
  -lco GEOMETRY_NAME=geom \
  -lco FID=id \
  -overwrite

その後、DBeaverをリフレッシュするとmedical_facilitiesテーブルが表示されます。

それでは取り込んだデータをDBeaverを使って見ていきましょう。テーブル内のdataタブを開くとDBの中身を確認できます。また、中身の表示方法をGridからSpatialに変更すると下画像のように地図に表示することができます。

スクリーンショット 2026-08-05 16.21.21.png

関数を使ってみる

PostGISには空間演算を行うための空間関数が用意されています。
GISとして動く様子が伝わりやすい関数をピックアップしてみました。

分類 関数・演算子 何ができるか
確認 ST_SRID ジオメトリに設定されたSRIDを取得する
確認 ST_AsText ジオメトリをWKT形式で表示する
出力 ST_AsGeoJSON ジオメトリやレコードをGeoJSON形式の文字列へ変換する
変換 ST_Transform ジオメトリを別の空間参照系へ座標変換する
距離 ST_Distance 2つのジオメトリ間の距離を計算する
範囲検索 ST_DWithin 指定した距離以内に存在するか判定する
空間関係 ST_Within あるジオメトリが別のジオメトリの内部にあるか判定する
空間関係 ST_Intersects 2つのジオメトリが点を共有しているか判定する
範囲作成 ST_Buffer ジオメトリの周囲に指定距離の領域を作成する
近傍検索 <-> GiSTインデックスを利用したKNN近傍検索で距離順に並べる

ここからは、ピックアップしたコマンドを実際に叩いてみます。

ジオメトリを読みやすいWKTで表示する

SELECT
  p04_004 AS specialty,
  ST_AsText(geom) AS location
FROM medical_facilities
WHERE p04_004 = '歯科' LIMIT 5;

結果として、診療科目1が『歯科』と一致する医療機関の位置情報を取得できました。

specialty location
歯科 POINT(131.515383 33.1998214)
歯科 POINT(131.4324019 33.0043422)
歯科 POINT(131.4758285 32.9724497)
歯科 POINT(131.4761782 32.97398195)
歯科 POINT(131.5822865 32.9748558)

ジオメトリやレコードをGeoJSON形式の文字列へ変換する

ST_AsGeoJSON()でGeoJSONとして取得できます。

SELECT
  p04_004 AS specialty,
  ST_AsGeoJSON(geom) AS geometry
FROM medical_facilities
WHERE p04_004 = '歯科' LIMIT 1;

出力されたgeometryにGeoJSONが入ってました。

json
{
    "type":"Point",
    "coordinates":[131.515383,33.1998214]
}

大分駅付近から5km以内を探す

大分駅の座標(131.606 33.233)を基準として5kmを探します。
まず、ST_MakePointで大分駅のポイントを作成し、ST_SetSRIDで座標系をセットしています。今回取り込んだGeoJSONのSRIDは4326です。そのため、大分駅のポイントもSRID 4326で作成します。距離をメートル単位で計算するため、検索前に大分県で利用できる平面直角座標系第II系へST_Transformで変換し、ST_DWithinで範囲検索します。座標単位はメートルのため、第3引数には5000を渡します。

WITH origin AS (
  SELECT ST_SetSRID(
    ST_MakePoint(131.606, 33.233),
    4326
  ) AS geom
)
SELECT
  COUNT(*) AS facility_count
FROM medical_facilities AS m
CROSS JOIN origin AS o
WHERE ST_DWithin(
  ST_Transform(m.geom, 6670),
  ST_Transform(o.geom, 6670),
  5000
);

結果として、425件がヒットしました。

facility_count
425

終わりに

PostGISを導入することで、PostgreSQL上で地理空間データを保存し、距離検索や範囲検索、交差判定などを実行できるようになりました。静的なマップタイルだけで情報を配信する構成と比べると、データベース側で検索条件を動的に変更したり、属性情報と組み合わせて集計したりしやすくなります。
今回は扱いませんでしたが、PostGISでは次のような処理も実行できます。

  • ポリゴン内に存在する施設の検索
  • ポリゴン同士の交差判定
  • 重複領域の算出
  • 最寄り施設の検索
  • バッファ領域の作成
  • 空間インデックスを利用した高速な近傍検索

PostGISには、まだ把握できていないものも含めて多数の空間関数があります。
今後も、実際のGIS開発で必要になる機能を試しながら学んでいきたいと思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?