GanosBase Geometry は AnalyticDB for PostgreSQL 向けの空間ジオメトリ拡張です。OpenGIS 標準に準拠し、2D (X, Y)、3D (X, Y, Z)、および 4D (X, Y, Z, M) の空間データをサポートします。GanosBase Geometry は PostGIS と完全互換であり、既存アプリケーションをスムーズに移行できます。GanosBaseGanosBase
GanosBase Geometry を使用すると、以下の操作が可能です。
ポイント、ラインストリング、ポリゴンを単一のジオメトリ列に格納
近接検索や包含検索を高速化するための GiST (Generalized Search Tree) 空間インデックスを構築
PostGIS のすべての空間関数および演算子を利用
前提条件
作業を開始する前に、以下の要件を満たしていることを確認してください。
AnalyticDB for PostgreSQL インスタンス
ganos_spatialref拡張およびganos_geometry拡張がインストール済み — インストールを依頼するにはチケットを送信してください
クイックスタート
以下の手順では、ジオメトリテーブルの作成、データの追加、空間インデックスの構築、空間クエリの実行という一連のワークフローを説明します。
ステップ 1:ジオメトリテーブルの作成
次の 2 つの方法があります。ジオメトリタイプが事前に分かっている場合は方法 1 を、既存のテーブルにジオメトリ列を追加する場合は方法 2 を使用してください。
方法 1 — CREATE TABLE 文でジオメトリ列を定義:
CREATE TABLE roads (
id int4,
road_name varchar(25),
geom geometry(LINESTRING, 3857)
) DISTRIBUTED BY (id);方法 2 — 既存のテーブルにジオメトリ列を追加:
CREATE TABLE roads (
id int4,
road_name varchar(25)
) DISTRIBUTED BY (id);
SELECT AddGeometryColumn('roads', 'geom', 3857, 'LINESTRING', 2);両方の例で使用されている SRID 3857 は Web メルカトル図法 (EPSG:3857) を示しており、座標はメートル単位で表されます。ご利用のデータの座標参照系に一致する SRID を選択してください。ステップ 2:ジオメトリ制約の追加
データ挿入前にジオメトリの有効性を強制するには、次のコマンドを実行します。
ALTER TABLE roads
ADD CONSTRAINT geometry_valid_check CHECK (ST_IsValid(geom));ステップ 3:ジオメトリデータの挿入
ST_GeomFromText を使用して、Well-Known Text (WKT) 文字列をジオメトリ値に変換します。この関数には WKT 表現と SRID を指定します。
座標は X Y(経度 緯度)の形式で指定します。経度が先に来るのは、X 軸を表すためです。SRID 3857 の場合、座標は角度ではなくメートル単位で表されます。
INSERT INTO roads (id, geom, road_name) VALUES
(1, ST_GeomFromText('LINESTRING(191232 243118,191108 243242)', 3857), '北五環路'),
(2, ST_GeomFromText('LINESTRING(189141 244158,189265 244817)', 3857), '東五環路'),
(3, ST_GeomFromText('LINESTRING(192783 228138,192612 229814)', 3857), '南五環路'),
(4, ST_GeomFromText('LINESTRING(189412 252431,189631 259122)', 3857), '西五環路'),
(5, ST_GeomFromText('LINESTRING(190131 224148,190871 228134)', 3857), '東長安街'),
(6, ST_GeomFromText('LINESTRING(198231 263418,198213 268322)', 3857), '西長安街');挿入された行を確認するには、ST_AsText を使用してジオメトリを WKT 形式で読み取ります。
SELECT id, ST_AsText(geom) AS geom, road_name FROM roads;期待される出力結果:
id | geom | road_name
----+-----------------------------------------+-----------------------
1 | LINESTRING(191232 243118,191108 243242) | 北五環路
2 | LINESTRING(189141 244158,189265 244817) | 東五環路
3 | LINESTRING(192783 228138,192612 229814) | 南五環路
4 | LINESTRING(189412 252431,189631 259122) | 西五環路
5 | LINESTRING(190131 224148,190871 228134) | 東長安街
6 | LINESTRING(198231 263418,198213 268322) | 西長安街
(6 rows)ステップ 4:GiST 空間インデックスの作成
GiST インデックスは、バウンディングボックスの重複や包含チェックなどの空間クエリを高速化します。ジオメトリ列に対してインデックスを作成した後、統計情報を更新するために VACUUM ANALYZE を実行します。
-- 標準の 2D インデックス
CREATE INDEX sp_geom_index ON roads USING GIST (geom);
-- N ディメンションインデックス (3D または 4D データ用)
-- CREATE INDEX sp_geom_index_nd ON roads USING GIST (geom gist_geometry_ops_nd);
VACUUM ANALYZE roads (geom);ステップ 5:空間クエリの実行
以下の例では、2 つのサンプルテーブルを使用します。クエリを実行する前に、これらのテーブルを作成し、ご利用のデータでテーブルを設定してください。
bc_roads — 道路ネットワーク:
| 列 | 型 | 説明 |
|---|---|---|
gid | integer | 一意の ID |
name | character varying | 道路名 |
the_geom | geometry | 位置ジオメトリ (ラインストリング) |
bc_municipality — 市町村の境界:
| 列 | 型 | 説明 |
|---|---|---|
gid | integer | 一意の ID |
code | integer | 一意のコード |
name | character varying | 市または町の名称 |
the_geom | geometry | 位置ジオメトリ (ポリゴン) |
ジオメトリの測定
ST_Length および ST_Area を使用して、距離や面積を計算します。これらの関数は、ジオメトリの座標参照系に基づく単位(SRID 3857 の場合はメートル)で結果を返します。
-- 道路の総延長(キロメートル単位)
SELECT SUM(ST_Length(the_geom)) / 1000 AS km_roads FROM bc_roads; km_roads
------------------
70842.1243039643
(1 row)-- 特定の市町村の面積(ヘクタール単位)
SELECT ST_Area(the_geom) / 10000 AS hectares
FROM bc_municipality
WHERE name = 'PRINCE GEORGE'; hectares
------------------
32657.9103824927
(1 row)空間関係のテスト
GanosBase Geometry は PostGIS のすべての空間関係関数をサポートしています。以下の表に、最も一般的な関数を示します。
| 関数 | 戻り値が true となる条件 |
|---|---|
ST_Contains(A, B) | A が B を完全に含む |
ST_Covers(A, B) | A が B を覆う(境界を含む) |
ST_Within(A, B) | A が B の内部に完全に含まれる |
ST_Intersects(A, B) | A と B がいずれかの点を共有 |
ST_Disjoint(A, B) | A と B が共有点を持たない |
ST_Touches(A, B) | A と B が境界上の点のみを共有 |
ST_Overlaps(A, B) | A と B が重複するが、どちらも他方を含まない |
ST_Crosses(A, B) | A と B が交差する(次元が異なる交差) |
ST_Relate(A, B, matrix) | A と B が指定された DE-9IM パターンを満たす |
例 — ST_Contains を使用して市町村ごとの道路延長を算出:
SELECT m.name, SUM(ST_Length(r.the_geom)) / 1000 AS roads_km
FROM bc_roads AS r, bc_municipality AS m
WHERE ST_Contains(m.the_geom, r.the_geom)
GROUP BY m.name
ORDER BY roads_km;例 — ST_Covers を使用して 2 つの円のカバー範囲を比較:
SELECT
ST_Covers(smallc, smallc) AS smallinsmall,
ST_Covers(smallc, bigc) AS smallcoversbig,
ST_Covers(bigc, ST_ExteriorRing(bigc)) AS bigcoversexterior,
ST_Contains(bigc, ST_ExteriorRing(bigc)) AS bigcontainsexterior
FROM (
SELECT
ST_Buffer(ST_GeomFromText('POINT(1 2)'), 10) AS smallc,
ST_Buffer(ST_GeomFromText('POINT(1 2)'), 20) AS bigc
) AS foo; smallinsmall | smallcoversbig | bigcoversexterior | bigcontainsexterior
--------------+----------------+-------------------+---------------------
t | f | t | f
(1 row)ST_CoversとST_Containsは、境界点の扱い方が異なります。ST_Coversは A が B の境界を覆う場合に true を返しますが、ST_Containsはそうしません。
例 — ST_Disjoint を使用してポイントとラインの非共有点をテスト:
-- ライン上にないポイント:非共有点
SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 2 0, 0 2 )'::geometry);
-- 結果:t
-- ライン上のポイント:非共有点ではない
SELECT ST_Disjoint('POINT(0 0)'::geometry, 'LINESTRING ( 0 0, 0 2 )'::geometry);
-- 結果:f例 — ST_Overlaps を使用して重複と交差をテスト:
SELECT ST_Overlaps(a, b) AS a_overlap_b,
ST_Crosses(a, b) AS a_crosses_b,
ST_Intersects(a, b) AS a_intersects_b,
ST_Contains(b, a) AS b_contains_a
FROM (
SELECT ST_GeomFromText('POINT(1 0.5)') AS a,
ST_GeomFromText('LINESTRING(1 0, 1 1, 3 5)') AS b
) AS foo; a_overlap_b | a_crosses_b | a_intersects_b | b_contains_a
-------------+-------------+----------------+--------------
f | f | t | t例 — ST_Relate を使用して空間関係をテスト:
SELECT ST_Relate(ST_GeometryFromText('POINT(1 2)'), ST_Buffer(ST_GeometryFromText('POINT(1 2)'), 2), '0FFFFF212'); st_relate
-----------
t例 — ST_Touches を使用してポイントがラインに接しているかをテスト:
-- 内部ポイント:接していない(ST_Touches は境界接触のみを対象とする)
SELECT ST_Touches('LINESTRING(0 0, 1 1, 0 2)'::geometry, 'POINT(1 1)'::geometry);
-- 結果:f
-- ラインの端点:接している
SELECT ST_Touches('LINESTRING(0 0, 1 1, 0 2)'::geometry, 'POINT(0 2)'::geometry);
-- 結果:t例 — ST_Within を使用してネストされた円の包含を確認:
SELECT
ST_Within(smallc, smallc) AS 小円_内_小円,
ST_Within(smallc, bigc) AS 小円_内_大円,
ST_Within(bigc, smallc) AS 大円_内_小円,
ST_Within(ST_Union(smallc, bigc), bigc) AS 和集合_内_大円,
ST_Within(bigc, ST_Union(smallc, bigc)) AS 大円_内_和集合,
ST_Equals(bigc, ST_Union(smallc, bigc)) AS 大円_等_和集合
FROM (
SELECT
ST_Buffer(ST_GeomFromText('POINT(50 50)'), 20) AS smallc,
ST_Buffer(ST_GeomFromText('POINT(50 50)'), 40) AS bigc
) AS foo; smallinsmall | smallinbig | biginsmall | unioninbig | biginunion | bigisunion
--------------+------------+------------+------------+------------+------------
t | t | f | t | t | t
(1 row)ジオメトリの有効性チェック
ST_IsSimple を使用して、ジオメトリが自己交差していないかを確認し、ST_NRings を使用してポリゴン内のリング数をカウントします。
-- 有効な閉じたリング(シンプルポリゴン)
SELECT ST_IsSimple(ST_GeomFromText('POLYGON((1 2, 3 4, 5 6, 1 2))'));
-- 結果:t
-- 自己交差するラインストリング(シンプルではない)
SELECT ST_IsSimple(ST_GeomFromText('LINESTRING(1 1,2 2,2 3.5,1 3,1 2,2 1)'));
-- 結果:f
-- 複数のリングを持つ最大面積の市町村を検索
SELECT gid, name, ST_Area(the_geom) AS area
FROM bc_municipality
WHERE ST_NRings(the_geom) > 1
ORDER BY area DESC
LIMIT 1; gid | name | area
-----+--------+------------------
12 | Anning | 257374619.430216
(1 row)ステップ 6:拡張の削除
GanosBase Geometry をアンインストールするには、次の順序で拡張を削除します。
DROP EXTENSION ganos_geometry;
DROP EXTENSION ganos_spatialref;拡張を削除すると、すべてのジオメトリ関数および演算子が削除されます。ジオメトリ列を持つテーブルは、拡張を再インストールするまで空間関数を使用できなくなります。
SQL リファレンス
GanosBase Geometry は PostGIS と完全互換です。サポートされている関数および演算子の完全なリストについては、「PostGIS リファレンス」をご参照ください。