16.4. Lesson: 空間検索

地理空間情報のクエリは、その他のデータベースのクエリと変わりなく、同じように利用できます。PostGISをインストールすることでデータベースのクエリの機能が追加されます。

このレッスンの目的は地理空間関数が、一般的な地理空間以外の関数と同様に導入できることを明らかにすることです。

16.4.1. 地理空間オペレータ

ある地点(X,Y)から2度距離がある地点を特定したい場合以下の操作ができます

select *
from people
where st_distance(the_geom,'SRID=4326;POINT(33 -34)') < 2;

結果:

 id |     name     | house_no | street_id |   phone_no    |   the_geom
----+--------------+----------+-----------+---------------+-----------------
  6 | Fault Towers |       34 |         3 | 072 812 31 28 | 01010008040C0
(1 row)

ノート

上記_geom valueは当サイトのスペースを残すため削除されました。human-readable coordinatesを確認するためには、”View a point as WKT”セクションと類似した操作で確認することができます。

上述のクエリが2度という空間内にある地点をすべてかえすということはどうしたらわかりますでしょうか?なぜ2メートル、あるいはその他の単位ではないのでしょうか?

結果をご確認ください

16.4.2. 地理空間インデックス

地理空間のインデックスも定義することができます。地理空間のインデックスはクエリを高速化します。地理空間のインデックスをジオカラムに作成するには:

CREATE INDEX people_geo_idx
  ON people
  USING gist
  (the_geom);

\d people

結果:

Table "public.people"
   Column   |         Type          |                Modifiers
 -----------+-----------------------+----------------------------------------
  id        | integer               | not null default
            |                       | nextval('people_id_seq'::regclass)
  name      | character varying(50) |
  house_no  | integer               | not null
  street_id | integer               | not null
  phone_no  | character varying     |
  the_geom  | geometry              |
Indexes:
  "people_pkey" PRIMARY KEY, btree (id)
  "people_geo_idx" gist (the_geom)  <-- new spatial key added
  "people_name_idx" btree (name)
Check constraints:
  "people_geom_point_chk" CHECK (st_geometrytype(the_geom) = 'ST_Point'::text
  OR the_geom IS NULL)
Foreign-key constraints:
  "people_street_id_fkey" FOREIGN KEY (street_id) REFERENCES streets(id)

16.4.3. Try Yourself moderate

そのジオメトリ列が空間索引付けされたように、都市のテーブルを変更します。

結果の確認

16.4.4. PostGIS 空間関数デモ

PostGIS の空間関数のデモを行うため、いくつかの(架空の)データを含む新しいデータベースを作成します。

開始のため、新しいデータベース (第一にpsql シェルが存在する)を作成します:

createdb postgis_demo

Remember to install the postgis extensions:

psql -d postgis_demo -c "CREATE EXTENSION postgis;"

次に、提供されたデータを:kbd: `exercise_data / PostGISの/`ディレクトリの中にインポートします。手順については前のレッスンを参照していただきますが、新しいデータベースへの新しいPostGISの接続を作成する必要があることを覚えておいてください。端末から、または、SPITを経由して、インポートできます。次のデータベーステーブルにファイルをインポートします:

  • points.shpbuilding

  • lines.shproad

  • polygons.shpregion

いつものように、 PostGISのレイヤーを追加 ダイアログでこれらの3つのデータベースレイヤーをQGISにロードします。それらの属性テーブルを開くと、 id フィールドとPostGISのインポートによって作成された gid フィールドの両方があることに注意。

テーブルはインポートされていますので、データを照会するためのPostGISを使用できます。端末(コマンドライン)に戻って以下を実行することによりpsqlのプロンプトを入力してください:

psql postgis_demo

QGISでそれらを開き、結果を見ることができるように、それらからのビューを作成することによってこれらのselect文の一部をデモします。

16.4.4.1. 場所による選択

クワズール地域のすべての建物を取得する:

SELECT a.id, a.name, st_astext(a.the_geom) as point
  FROM building a, region b
    WHERE st_within(a.the_geom, b.the_geom)
    AND b.name = 'KwaZulu';

結果:

 id | name |                  point
----+------+------------------------------------------
 30 | York | POINT(1622345.23785063 6940490.65844485)
 33 | York | POINT(1622495.65620524 6940403.87862489)
 35 | York | POINT(1622403.09106394 6940212.96302097)
 36 | York | POINT(1622287.38463732 6940357.59605424)
 40 | York | POINT(1621888.19746548 6940508.01440885)
(5 rows)

あるいは、それからビューを作成する場合:

CREATE VIEW vw_select_location AS
  SELECT a.gid, a.name, a.the_geom
    FROM building a, region b
      WHERE st_within(a.the_geom, b.the_geom)
      AND b.name = 'KwaZulu';

レイヤーとしてビューを追加し、QGISで表示:

../../../_images/kwazulu_view_result.png

16.4.4.2. 近傍の選択

北海道地区に隣接するエリアの名称すべてのリストを表示します。

SELECT b.name
  FROM region a, region b
    WHERE st_touches(a.the_geom, b.the_geom)
    AND a.name = 'Hokkaido';

結果:

    name
--------------
 Missouri
 Saskatchewan
 Wales
(3 rows)

見た目として:

CREATE VIEW vw_regions_adjoining_hokkaido AS
  SELECT b.gid, b.name, b.the_geom
    FROM region a, region b
      WHERE TOUCHES(a.the_geom, b.the_geom)
      AND a.name = 'Hokkaido';

QGISでは:

../../../_images/adjoining_result.png

不足している地域(クイーンズランド州)に注意してください。これは、トポロジエラーに起因する可能性があります。このようなアーティファクトは、データの潜在的な問題のために警告することがあります。データが持つかもしれない異常に巻き込まれることなく、この謎を解決するために、代わりにバッファ交差を使用できます:

CREATE VIEW vw_hokkaido_buffer AS
  SELECT gid, ST_BUFFER(the_geom, 100) as the_geom
    FROM region
      WHERE name = 'Hokkaido';

北海道の周囲に100mのバッファを作成します。

暗いエリアがバッファです:

../../../_images/hokkaido_buffer.png

バッファを使用して選択します:

CREATE VIEW vw_hokkaido_buffer_select AS
  SELECT b.gid, b.name, b.the_geom
    FROM
    (
      SELECT * FROM
        vw_hokkaido_buffer
    ) a,
    region b
    WHERE ST_INTERSECTS(a.the_geom, b.the_geom)
    AND b.name != 'Hokkaido';

このクエリでは、元のバッファ・ビューは、他のテーブルがされるように使用されます。これは別名 a を与えられ、その幾何形状フィールド region テーブル(別名 ba.the_geom が、それと交差するすべての多角形を選択するために使用されます。しかし北海道自体はこのselect文から除外されます。必要なのは北海道自体ではなく、それに隣接する領域だけなので。

QGISでは:

../../../_images/hokkaido_buffer_select.png

バッファを作成するための余分な工程を経ることなく、与えられた距離内のすべてのオブジェクトを選択することも可能である:

CREATE VIEW vw_hokkaido_distance_select AS
  SELECT b.gid, b.name, b.the_geom
    FROM region a, region b
      WHERE ST_DISTANCE (a.the_geom, b.the_geom) < 100
      AND a.name = 'Hokkaido'
      AND b.name != 'Hokkaido';

これは、中間バッファステップを必要とせずに、同じ結果を達成します:

../../../_images/hokkaido_distance_select.png

16.4.4.3. 一意の値を選択する

クイーンズランド州に所在する建物の所在地の村の名前をリストにします。

SELECT DISTINCT a.name
  FROM building a, region b
    WHERE st_within(a.the_geom, b.the_geom)
    AND b.name = 'Queensland';

結果:

  name
---------
 Beijing
 Berlin
 Atlanta
(3 rows)

16.4.4.4. その他の事例

CREATE VIEW vw_shortestline AS
  SELECT b.gid AS gid, ST_ASTEXT(ST_SHORTESTLINE(a.the_geom, b.the_geom)) as
    text, ST_SHORTESTLINE(a.the_geom, b.the_geom) AS the_geom
    FROM road a, building b
      WHERE a.id=5 AND b.id=22;

CREATE VIEW vw_longestline AS
  SELECT b.gid AS gid, ST_ASTEXT(ST_LONGESTLINE(a.the_geom, b.the_geom)) as
    text, ST_LONGESTLINE(a.the_geom, b.the_geom) AS the_geom
    FROM road a, building b
      WHERE a.id=5 AND b.id=22;
CREATE VIEW vw_road_centroid AS
  SELECT a.gid as gid, ST_CENTROID(a.the_geom) as the_geom
    FROM road a
      WHERE a.id = 1;

CREATE VIEW vw_region_centroid AS
  SELECT a.gid as gid, ST_CENTROID(a.the_geom) as the_geom
    FROM region a
      WHERE a.name = 'Saskatchewan';
SELECT ST_PERIMETER(a.the_geom)
  FROM region a
    WHERE a.name='Queensland';

SELECT ST_AREA(a.the_geom)
  FROM region a
    WHERE a.name='Queensland';
CREATE VIEW vw_simplify AS
  SELECT gid, ST_Simplify(the_geom, 20) AS the_geom
    FROM road;

CREATE VIEW vw_simplify_more AS
  SELECT gid, ST_Simplify(the_geom, 50) AS the_geom
    FROM road;
CREATE VIEW vw_convex_hull AS
  SELECT
    ROW_NUMBER() over (order by a.name) as id,
    a.name as town,
    ST_CONVEXHULL(ST_COLLECT(a.the_geom)) AS the_geom
    FROM building a
    GROUP BY a.name;

16.4.5. In Conclusion

PostGISのから新しいデータベース機能を使用して、空間オブジェクトを照会する方法を見てきました。

16.4.6. What’s Next?

次は、より複雑な幾何形状の構造と、それらをPostGISを使用して作成する方法を調査するつもりです。