第3章 よくある質問

1. どのような種類のジオメトリオブジェクトを格納できますか?
2. どのようにしてGISオブジェクトをデータベースへ登録したらよいですか?
3. どのようにして空間クエリ(spatial query)を組み立てたらよいですか?
4. どのようにして大きなテーブルでの空間クエリ(spatial query)をスピードアップしたらよいですか?
5. どうすれば,bounding boxが重なっているもののではなく,検索領域(search box)に本当に含まれるものを検索結果として得られますか?
6. PostgreSQLのR-Treeインデックスがサポートされないのはなぜですか?
7. なぜAddGeometryColumn()関数などのOpenGISの要素(stuff)を使った方が良いのでしょうか?
8. あるオブジェクトの範囲に含まれる全てのオブジェクトを検索する最も良い方法はなんでしょう?
9. どのようにしてクエリの中で座標の投影法変換を行えばよいでしょうか?

1. どのような種類のジオメトリオブジェクトを格納できますか?

ポイント,ライン,ポリゴン,マルチポイント,マルチライン,マルチポリゴン,ジオメトリ集合を登録することができます.これらは,Open GIS WellKnownテキストフォーマット(3次元拡張付)に記述されています.

2. どのようにしてGISオブジェクトをデータベースへ登録したらよいですか?

最初に,GISデータを保持するための"geometry"タイプのカラムを持つテーブ ルを作る必要があります.psqlでデータベースに接続し,以下のSQLを試してください:

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

もし,ジオメトリカラムの追加に失敗したのなら,おそらくこのデータベースにはPostGISの関数とオブジェクトがロードされていません.インストール説明書を参照してください.

これで,SQLのinsert分を使ってテーブルにジオメトリを登録することができます.GISオブジェクトはそれ自身Open GISコンソーシアムの"well-known text"フォーマットでフォーマットされます:

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

他のGISオブジェクトについての詳しい情報については,オブジェクトリファレンスを参照してください.

表中のGISデータを見るには以下のようにします:

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

返値はこのようになるでしょう:

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

3. どのようにして空間クエリ(spatial query)を組み立てたらよいですか?

PostgreSQLで利用可能な空間演算子がたくさんあり,それらのいくつかはインデックスサポートを提供するためにPostGISによって実現されています.

インデックスをサポートしたspatial queryを実行するために,次の重要な単純化の仮定を利用する「overlap演算子("overlap operator")」(&&)を使用しなければなりません:全ての図形はbounding boxによって表現されるでしょう.

bounding boxを図形の代わりに使うことは制限的な仮定ですが,空間インデックス機能を提供する上で重要な仮定であると考えています.商用空間データベースは同じ仮定を使っています-- bounding boxは,ほとんどの空間インデックススキームにとって重要です.

ユーザの視点で最も重要な空間演算子はoverlap演算子"&&"です.これは,ある図形のbounding boxが他の図形のbounding boxに重なるかどうかをテストします.&&を使った空間クエリの例は次のようになります:

  SELECT id,name FROM GTEST WHERE GEOM && 'BOX3D(3 4,4 5)'::box3d

問合せのために使われるbounding boxは,キャスト操作"::box3d"を使ってbox3dとして明示的に宣言しなければならないことに注意してください.

4. どのようにして大きなテーブルでの空間クエリ(spatial query)をスピードアップしたらよいですか?

大きなテーブルでの高速な問合せは,(トランザクションのサポートとともに)良いインデックスを持つ空間データベースの重要な存在理由です.

geometryカラムを持つテーブルに空間インデックスを構築するために,以下のように"CREATE INDEX"関数を使ってください:

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

"USING GIST"オプションは,サーバにGiST(Generalized Search Tree)インデックスを使うことを指示します."gist_geometry_ops"の記述(reference to)は,インデックスを作るために用いる固有の比較演算子のセットを指示します:"gist_geometry_ops"はPostGISの拡張の一部です.

注: PostgreSQL version 7.1.xでは,インデックス作成コマンドにWITH (ISLOSSY)を追加することで,"lossy"インデックスを明確に要求することができます.PostgreSQL 7.2.xと上記の全てのGiSTインデックスは,lossyとみなされます.lossyインデックスは,インデックスの作成に代用のオブジェクト(空間の場合bounding box)を用います.

5. どうすれば,bounding boxが重なっているもののではなく,検索領域(search box)に本当に含まれるものを検索結果として得られますか?

'&&'演算子は,bounding_boxの重なりだけをチェックしますが,本当に検索領域(search box)と交差する図形だけを得るために,"truly_inside()"関数を使うことができます.例えば,高速なインデックス検索のための"&&"と結果集合の厳密な最終チェックのためtruly_inside()とを組み合わせて使うことによって,検索領域(serch box)に含まれる図形だけを得ることができます(これは現在のところsearch boxについてのみ上手くいき,任意の勝手なジオメトリでは上手くいかないことに注意してください):

  SELECT [COLUMN1],[COLUMN2],AsText([GEOMETRYCOLUMN])
    	FROM [TABLE] WHERE [GEOM_COLUMN] && [BOX3d] 
     AND	truly_inside([GEOM_COLUMN],[BOX3d]);

6. PostgreSQLのR-Treeインデックスがサポートされないのはなぜですか?

PostGISの初期のバージョンではPostgreSQLのR-Treeインデックスを使っていました.しかしながら,バージョン0.6からPostgreSQLのR-Treeは完全に切り捨てられ,空間インデックスはGist上のR-Tree(R-Tree-over-GiST)スキームで提供されます.

我々のテストはネイティブのR-TreeとGiSTの検索速度は匹敵することを示しています.ネイティブのPostgreSQLのR-Treesは,GIS機能として使う場合,好ましくない2つの制限があります(これらの制限は現在のPostgreSQLのネイティブR-Treeの実装が原因で,一般的なR-Treeのコンセプトが原因でないことに注意してください):

  • PostgreSQLのR-Treeインデックスは,8Kより大きいサイズの図形を扱うことができません.GisTインデックスは,図形そのものをbounding boxで代用する"lossy"トリックを使うことで,扱うことができます.

  • PostgreSQLのR-Treeインデックスは"null safe"ではありません.そのため,nullジオメトリを含むジオメトリカラムのインデックス作成は失敗するでしょう.

7. なぜAddGeometryColumn()関数などのOpenGISの要素(stuff)を使った方が良いのでしょうか?

もし,OpenGISサポート関数を使いたくない場合,使う必要はありません.単純に,CREATEステートメントでジオメトリカラムを定義する,古いバージョンとしてテーブルを作成てください.全てのジオメトリのSRIDは-1となり,OpenGISメタデータテーブルは適切に埋められないでしょう.しかしながら,このことはほとんどのPostGISベースのアプリケーションに失敗を引き起こし,通常あなたにジオメトリテーブル作成するためにAddGeometryColumn()を使うことを勧めるでしょう.

Mapserverは,geometry_columnsのめたデータを利用するアプリケーションの一つです.特にMapserverは,ジオメトリカラムのSRIDを正しい地図の投影法への図形の即時(on-the-fly)投影法変換を行うために利用します.

8. あるオブジェクトの範囲に含まれる全てのオブジェクトを検索する最も良い方法はなんでしょう?

もっとも効果的にデータベースを使うために,範囲のテストbounding boxのテスト組み合わせた範囲のクエリを実行することが一番です:bounding boxテストは空間インデックスを使い,範囲テストが適用されるデータのサブセットへの高速なアクセスを提供します.

たとえば,POINT(1000 1000)から100メートル以内の全てのオブジェクトを見つけるには,以下のクエリが上手く働くでしょう:

  SELECT * 
  FROM GEOTABLE 
  WHERE 
    GEOM && GeometryFromText('BOX3D(900 900,1100 1100)',-1)
  AND
  Distance(GeometryFromText('POINT(1000 1000)',-1),GEOM) < 100;

9. どのようにしてクエリの中で座標の投影法変換を行えばよいでしょうか?

投影法の変換を行うためには,元の座標系と目的の座標気の両方がSPATIAL_REF_SYS tableで定義されていなければなりません.そして,投影法を変換するジオメトリは,そのSRIDがすでにセットされていなければなりません.一度行えば,投影法 の変換は要求された目的のSRIDを参照するのと同じぐらい簡単です.

  SELECT Transform(GEOM,4269) FROM GEOTABLE;