第3章 よくある質問

3.1. 格納できるジオメトリオブジェクトにはどのような種類がありますか?
3.2. たいへん混乱しました.ジオメトリとジオグラフィのどちらを使うべきでしょうか?
3.3. もっとジオグラフィについて聞きたいです. たとえば, 領域がどの大きさまで,ジオグラフィカラムにデータを詰め込めて,合理的な答えが得られるのでしょうか,とか. 極,全データが半球上になければならない(SQL Serber 2008はそう),速度等の制限はあるのでしょうか,とか.
3.4. GISオブジェクトをデータベースに挿入するにはどうしますか?
3.5. 空間クエリを作成するにはどうするのですか?
3.6. 大きなテーブルでの空間クエリの速度向上はどうするのですか?
3.7. なぜPostgreSQLのR-Treeインデクスをサポートしないのですか?
3.8. なぜ AddGeometryColumn() 関数と他のOpsnGIS関数を使うべきなのですか?
3.9. 半径内にあるオブジェクトを全て検索する最善の方法は何ですか?
3.10. クエリの一部として投影変換を実現するにはどうしますか?
3.11. ST_AsEWKT と ST_AsText を,かなり大きいジオメトリで実行すると,空のフィールドが返りました.どうしたら良いですか?
3.12. ST_Intersectsを使うと,二つのジオメトリがインタセクトしているのに,インタセクトしていないと言います.どうしたら良いですか?

3.1.

格納できるジオメトリオブジェクトにはどのような種類がありますか?

ポイント,ライン,ポリゴン,マルチポイント,マルチライン,マルチポリゴン,ジオメトリコレクションが格納できます.これらは Open GIS Well Known Text Format で規定されています(XYZ,XYM,XYZM拡張付き) .現在はサポートされているデータ型は2種類あります. 測量に使われる平面座標系を使用する標準OGCジオメトリデータ型と,極座標系を使用するジオグラフィデータ型です. ジオグラフィデータ型は WGS 84 極座標系 (SRID:4326) のみサポートします.

3.2.

たいへん混乱しました.ジオメトリとジオグラフィのどちらを使うべきでしょうか?

短い答: ジオグラフィは長距離の測定をサポートする新しいデータ型です. ジオグラフィを使う場合は,平面座標系についてあまり多く学習する必要がありません. 行うことが距離や長さの計測に限定され,かつ世界中からのデータを持っている場合は,一般的にジオグラフィが最善です. ジオメトリは古いデータ型で,サポートする関数が多く,サードパーティからの多大なサポートがえられます. 空間参照系に慣れているか,空間参照系 (SRID)が単一で済むような局所的なデータを扱っているか,あるいは,空間処理を多く行う必要がある場合には,ジオメトリが最善です. 現在サポートされているもの,サポートされていないものについては 「 PostGIS関数サポートマトリクス 」 を参照して下さい.

長い答: 「 ジオグラフィ型をジオメトリ型にして使用すべき時 」関数型マトリクス を参照して下さい.

3.3.

もっとジオグラフィについて聞きたいです. たとえば, 領域がどの大きさまで,ジオグラフィカラムにデータを詰め込めて,合理的な答えが得られるのでしょうか,とか. 極,全データが半球上になければならない(SQL Serber 2008はそう),速度等の制限はあるのでしょうか,とか.

その質問は相当深く複雑で,このセクションで十分に答えられません.「 ジオグラフィの高度なよくある質問 」 を参照して下さい.

3.4.

GISオブジェクトをデータベースに挿入するにはどうしますか?

まず,GISデータを保持するために "geometry" または "geogprahy" カラムを持つテーブルを作成します.ジオグラフィデータ型の格納は,ジオメトリデータ型とは若干異なります.ジオグラフィの格納については 「 ジオグラフィ基礎 」 を参照して下さい.

ジオメトリ: psql でデータベースに接続して,次のSQLを試してみて下さい.

CREATE TABLE gtest ( ID int4, NAME varchar(20) );
SELECT AddGeometryColumn('', 'gtest','geom',-1,'LINESTRING',2);

ジオメトリカラムの追加に失敗する場合は,もしかしたら PostGIS の関数とオブジェクトをデータベースにロードしていないのかも知れません.「 インストール 」 を参照して下さい.

これで,SQLのINSERTステートメントを使って,ジオメトリをテーブルに挿入することができます. GISオブジェクト自体は,OpenGISコンソーシアムの "well-known text" フォーマットを使っています.

INSERT INTO gtest (ID, NAME, GEOM) 
VALUES (
  1, 
  'First Geometry', 
  ST_GeomFromText('LINESTRING(2 3,4 5,6 5,7 8)', -1)
);

他のGISオブジェクトの詳細については object reference をご覧ください.

テーブル内にあるGISデータを表示するには,次のようにします.

SELECT id, name, ST_AsText(geom) AS geom FROM gtest;

返り値は次のようなかんじになります.

 id | name           | geom
----+----------------+-----------------------------
  1 | First Geometry | LINESTRING(2 3,4 5,6 5,7 8) 
(1 row)

3.5.

空間クエリを作成するにはどうするのですか?

他のデータベースクエリを作るのと同じで,返り値,関数,テストのSQLの組み合わせです.

空間クエリでは,クエリを作成する際に心を平静に保つための重要な二つの問題があります. ひとつは,使用することができる空間インデクスがあるか.もうひとつは,多数のジオメトリを相手に計算量の多い計算を行っているか.

一般的に,フィーチャーのバウンディングボックスがインタセクト(交差)しているかをテストするインタセクト演算子(&&)を使いたくなります.&&演算子が便利な理由は,速度向上のために空間インデクスが付けられているなら,&&演算子は空間インデクスを使うからです.これによって,クエリの速度はとてもとても速くなります.

また,検索結果をより狭めるために,Distance(), ST_Intersects(), ST_Contains(), ST_Within() などといった空間関数を使うことでしょう.ほとんどの空間クエリは,インデクスのテストと空間関数のテストを含みます.インデクスのテストで,返ってくるタプルを,求める条件に合致するかもしれないタプルのみとして,タプルの数を制限します.それから,空間関数で確実な条件のテストを行います.

SELECT id, the_geom 
FROM thetable 
WHERE 
  ST_Contains(the_geom,'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');

3.6.

大きなテーブルでの空間クエリの速度向上はどうするのですか?

大きなテーブルの速いクエリは,空間インデクスのレゾンデートルです(トランザクションサポートもそうですが).

geometry カラムを持つテーブルでの空間インデクスの構築は,"CREATE INDEX" 機能を使って,次のようにします.

CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometrycolumn] );

"USING GIST" オプションによって,サーバにGiST(Generalized Search Tree)インデクスを作るよう指示が渡ります.

[注意]

GiSTインデクスは,不可逆であると仮定します.不可逆インデクスの構築には,代理オブジェクト(空間インデクスの場合はバウンディングボックス)を使います.

PostgreSQLのクエリプランナがインデクスを作るべきかについて合理的な決定を行うよう,十分な情報を確実に持てるようにすべきです.そのために,ジオメトリテーブル上で "gather statistics" を実行しなければなりません.

PostgreSQL 8.0.x 以上では VACUUM ANALYZE コマンドを実行するだけです.

3.7.

なぜPostgreSQLのR-Treeインデクスをサポートしないのですか?

PostGISの,かつての版では,PostgreSQLのR-Treeインデクスを使っていましたが,0.6版でPostgreSQLのR-Treeは完全に捨てて,R-Tree-over-GiSTスキームによる空間インデクスを提供しています.

私たちの試験では,R-TreeとGiSTの検索速度は同程度であることが示されています.PostgreSQLのR-Treeには,GISフィーチャーで使うためには好ましくない二つの制限があります(これらの制限は現在のPostgreSQLネイティブのR-Tree実装についてであって,R-Tree一般の話ではありません).

  • PostgreSQLのR-Treeインデクスは,8K以上のサイズのフィーチャーは扱えません.GiSTインデクスはフィーチャー自体の代わりにバウンディングボックスを用いる「不可逆」トリックを使っているので扱うことができます.

  • PostgreSQLのR-Treeインデクスは「NULLセーフ」ではなく,NULLジオメトリを含むジオメトリカラムではインデクス作成に失敗します.

3.8.

なぜ AddGeometryColumn() 関数と他のOpsnGIS関数を使うべきなのですか?

OpenGISがサポートする関数を使いたくないのでしたら,使う必要はありません.単純に,ジオメトリカラムをCREATEステートメントで定義する古いやり方で作成して下さい.全てのジオメトリはSRIDが-1になり,OpenGISメタデータテーブルは適切に書き込まれません. しかし,これによって,ほとんどのPostGISベースのアプリケーションでは失敗しますので, 一般的には AddGeometryColumn() を用いることをお勧めします.

Mapserverは geometry_columns メタデータを使うアプリケーションのひとつです. 踏み込んで言えば,MpaserverはジオメトリカラムのSRIDを使って,正しい地図投影へのフィーチャーの自動投影変換を行います.

3.9.

半径内にあるオブジェクトを全て検索する最善の方法は何ですか?

データベースを最も効果的に使うには, 半径検索とバウンディングボックス検索を組み合わせた半径検索を行うのが最も良いです.バウンディングボックス検索で空間インデクスを使用するので,半径検索が適用されるサブセットへのアクセスが早くなります.

ST_DWithin(geometry, geometry, distance) 関数は,インデクス付きの距離検索を実行する手頃な方法です.この関数は,距離半径を十分に含む大きさの検索矩形を作成して, インデクス付きの結果サブセットに対して確実な距離検索を行います.

たとえば,POINT(1000 1000)から100メートル内の全てのオブジェクトを見つけるためには,次のクエリで動作します.

SELECT * FROM geotable 
WHERE ST_DWithin(geocolumn, 'POINT(1000 1000)', 100.0);

3.10.

クエリの一部として投影変換を実現するにはどうしますか?

投影変換を行うには,変換元と変換先双方の座標系がSPATIAL_REF_SYSテーブルに定義されていて, かつ投影変換されるジオメトリがそのSRIDを持っている必要があります.これが行われていると,投影変換は求める変換先SRIDを参照するのと同じぐらい簡単です. 次のクエリは,ジオメトリを NAD 84 経度緯度に投影しています.このクエリは the_geom が -1 (空間参照系が定義されていない) 場合のみ動作します.

SELECT ST_Transform(the_geom,4269) FROM geotable;

3.11.

ST_AsEWKT と ST_AsText を,かなり大きいジオメトリで実行すると,空のフィールドが返りました.どうしたら良いですか?

PgAdminまたは大きなテキストを表示しないその他のツールを使用しているのかも知れません. ジオメトリが十分に大きい場合,ツールには空として表示されます.本当にWKTで見たり出力したりしなければならない場合は,PSQLを使用して下さい.

				--To check number of geometries are really blank
				SELECT count(gid) FROM geotable WHERE the_geom IS NULL;

3.12.

ST_Intersectsを使うと,二つのジオメトリがインタセクトしているのに,インタセクトしていないと言います.どうしたら良いですか?

二つの場合がよくあります.ひとつは,ジオメトリが無効な場合です.この場合 ST_IsValid を見ます.もうひとつは,ST_AsTextで数字を切り捨てて表示されている分より後にたくさんの小数が付いている場合です.