Chapter 5. Räumliche Abfrage

Table of Contents

Der Sinn von räumlichen Datenbanken liegt darin Abfragen in der Datenbank ausführen zu können, die normalerweise Desktop-GIS-Funktionionalität verlangen würden. Um PostGIS effektiv verwenden zu können muss man die verfügbaren räumlichen Funktionen kennen, wissen wie sie in Abfragen verwendet werden und sicherstellen, dass für gute Performanz die passenden Indizes vorhanden sind.

5.1. Räumliche Beziehungen feststellen

Räumliche Beziehungen geben an wie zwei Geometrien miteinander interagieren. Sie sind die fundamentale Fähigkeit zum Abfragen von Geometrie.

5.1.1. Dimensionell erweitertes 9-Schnitte-Modell

Laut OpenGIS Simple Features Implementation Specification for SQL besteht der grundlegende Ansatz für den Vergleich zweier Geometrien darin, paarweise Tests der Schnittpunkte zwischen den Innen-, Rand- und Außenbereichen der beiden Geometrien durchzuführen und die Beziehung zwischen den beiden Geometrien auf der Grundlage der Einträge in der resultierenden 'Schnittpunkt'-Matrix zu klassifizieren".

In der Theorie der Punktmengentopologie werden die Punkte in einer Geometrie, die in den 2-dimensionalen Raum eingebettet ist, in drei Gruppen eingeteilt:

Grenze

Die Begrenzung einer Geometrie ist die Menge der Geometrien der nächstniedrigeren Dimension. Für POINTs, die eine Dimension von 0 haben, ist die Begrenzung die leere Menge. Die Begrenzung eines LINESTRING sind die beiden Endpunkte. Für POLYGONs ist die Begrenzung das Liniennetz der äußeren und inneren Ringe.

Innenbereich

Das Innere einer Geometrie sind die Punkte einer Geometrie, die nicht in der Begrenzung liegen. Für POINTs ist das Innere der Punkt selbst. Das Innere eines LINESTRING ist die Menge der Punkte zwischen den Endpunkten. Für POLYGONs ist das Innere die Fläche innerhalb des Polygons.

Äußeres

Das Äußere einer Geometrie ist der Rest des Raums, in den die Geometrie eingebettet ist; mit anderen Worten, alle Punkte, die sich nicht im Inneren oder auf dem Rand der Geometrie befinden. Es handelt sich um eine 2-dimensionale, nicht geschlossene Fläche.

Das Dimensionally Extended 9-Intersection Model (DE-9IM) beschreibt die räumliche Beziehung zwischen zwei Geometrien durch Angabe der Dimensionen der 9 Schnittpunkte zwischen den oben genannten Mengen für jede Geometrie. Die Schnittpunktdimensionen können formal in einer 3x3 Schnittpunktmatrix dargestellt werden.

Für eine Geometrie g werden Interior, Boundary, und Exterior mit den Bezeichnungen I(g), B(g), und E(g) bezeichnet. Außerdem bezeichnet dim(s) die Dimension einer Menge s mit dem Bereich {0,1,2,F}:

  • 0 => Punkt

  • 1 => Zeile

  • 2 => Fläche

  • F => leere Menge

Unter Verwendung dieser Notation lautet die Schnittpunktmatrix für zwei Geometrien a und b:

  Innenbereich Grenze Äußeres
Innenbereich dim( I(a) ∩ I(b) ) dim( I(a) ∩ B(b) ) dim( I(a) ∩ E(b) )
Grenze dim( B(a) ∩ I(b) ) dim( B(a) ∩ B(b) ) dim( B(a) ∩ E(b) )
Äußeres dim( E(a) ∩ I(b) ) dim( E(a) ∩ B(b) ) dim( E(a) ∩ E(b) )

Für zwei sich überschneidende polygonale Geometrien sieht dies folgendermaßen aus:

 
  Innenbereich Grenze Äußeres
Innenbereich

dim( I(a) ∩ I(b) ) = 2

dim( I(a) ∩ B(b) = 1

dim( I(a) ∩ E(b) ) = 2

Grenze

dim( B(a) ∩ I(b) ) = 1

dim( B(a) ∩ B(b) ) = 0

dim( B(a) ∩ E(b) ) = 1

Äußeres

dim( E(a) ∩ I(b) ) = 2

dim( E(a) ∩ B(b) ) = 1

dim( E(a) ∩ E(b) = 2

Von links nach rechts und von oben nach unten gelesen, wird die Kreuzungsmatrix als Textstring '212101212' dargestellt.

Weitere Informationen finden Sie unter:

5.1.2. Benannte räumliche Beziehungen

Um die Bestimmung allgemeiner räumlicher Beziehungen zu erleichtern, definiert das OGC SFS eine Reihe von genannten räumlichen Beziehungsprädikaten. PostGIS stellt diese als die Funktionen ST_Contains, ST_Crosses, ST_Disjoint, ST_Equals, ST_Intersects, ST_Overlaps, ST_Touches, ST_Within zur Verfügung. Es definiert auch die Nicht-Standard-Beziehungsprädikate ST_Covers, ST_CoveredBy und ST_ContainsProperly.

Räumliche Prädikate werden normalerweise als Bedingungen in SQL WHERE oder JOIN Klauseln verwendet. Die benannten räumlichen Prädikate verwenden automatisch einen räumlichen Index, wenn einer vorhanden ist, so dass es nicht notwendig ist, auch den Bounding-Box-Operator && zu verwenden. Zum Beispiel:

SELECT city.name, state.name, city.geom
FROM city JOIN state ON ST_Intersects(city.geom, state.geom);

Weitere Einzelheiten und Abbildungen finden Sie im PostGIS Workshop.

5.1.3. Allgemeine räumliche Beziehungen

In manchen Fällen reichen die genannten räumlichen Beziehungen nicht aus, um die gewünschten räumlichen Filterbedingungen zu schaffen.

Nehmen wir zum Beispiel einen linearen Datensatz, der ein Straßennetz darstellt. Es kann erforderlich sein, alle Straßenabschnitte zu identifizieren, die sich nicht in einem Punkt, sondern in einer Linie kreuzen (vielleicht um eine Geschäftsregel zu validieren). In diesem Fall bietet ST_Crosses nicht den erforderlichen räumlichen Filter, da es für lineare Merkmale true nur dann zurückgibt, wenn sie sich in einem Punkt kreuzen.

Eine zweistufige Lösung würde darin bestehen, zunächst den tatsächlichen Schnittpunkt (ST_Intersection) von Paaren von Straßenlinien zu berechnen, die sich räumlich schneiden (ST_Intersects), und dann zu prüfen, ob der ST_GeometryType des Schnittpunkts 'LINESTRING' ist (wobei Fälle, die GEOMETRYCOLLECTIONs von [MULTI]POINTs, [MULTI]LINESTRINGs usw. zurückgeben, korrekt behandelt werden).

Es ist klar, dass eine einfachere und schnellere Lösung wünschenswert ist.

Ein zweites Beispiel ist das Auffinden von Anlegestellen, die die Grenze eines Sees auf einer Linie schneiden und bei denen ein Ende der Anlegestelle auf dem Ufer liegt. Mit anderen Worten, wenn ein Kai innerhalb eines Sees liegt, aber nicht vollständig von diesem umschlossen ist, die Grenze eines Sees auf einer Linie schneidet und genau einer der Endpunkte des Kais innerhalb oder auf der Grenze des Sees liegt. Es ist möglich, eine Kombination von räumlichen Prädikaten zu verwenden, um die gewünschten Merkmale zu finden:

Diese Anforderungen können erfüllt werden, indem die vollständige DE-9IM-Schnittpunktmatrix berechnet wird. PostGIS bietet hierfür die Funktion ST_Relate:

SELECT ST_Relate( 'LINESTRING (1 1, 5 5)',
                  'POLYGON ((3 3, 3 7, 7 7, 7 3, 3 3))' );
st_relate
-----------
1010F0212

Um eine bestimmte räumliche Beziehung zu testen, wird ein Kreuzungsmatrixmuster verwendet. Dabei handelt es sich um die Matrixdarstellung, die um die zusätzlichen Symbole {T,*} erweitert wurde:

  • T => Schnittmenge ist nicht leer, d. h. sie liegt in {0,1,2}

  • * => ist mir egal

Mit Hilfe von Kreuzungsmatrixmustern können spezifische räumliche Beziehungen auf eine prägnantere Weise bewertet werden. Die Funktionen ST_Relate und ST_RelateMatch können zum Testen von Kreuzungsmatrixmustern verwendet werden. Für das erste obige Beispiel lautet das Schnittmatrixmuster, das zwei Linien angibt, die sich in einer Linie schneiden, '1*1***1**':

-- Find road segments that intersect in a line
SELECT a.id
FROM roads a, roads b
WHERE a.id != b.id
      AND a.geom && b.geom
      AND ST_Relate(a.geom, b.geom, '1*1***1**');

Für das zweite Beispiel lautet das Schnittmatrixmuster, das eine Linie teilweise innerhalb und teilweise außerhalb eines Polygons angibt, '102101FF2':

-- Find wharves partly on a lake's shoreline
SELECT a.lake_id, b.wharf_id
FROM lakes a, wharfs b
WHERE a.geom && b.geom
      AND ST_Relate(a.geom, b.geom, '102101FF2');

5.2. Räumliche Indizes verwenden

Bei der Erstellung von Abfragen mit räumlichen Bedingungen ist es für eine optimale Leistung wichtig, dass ein räumlicher Index verwendet wird, sofern ein solcher existiert (siehe Section 4.9, “Räumliche Indizes”). Zu diesem Zweck muss ein räumlicher Operator oder eine indexfähige Funktion in einer WHERE oder ON Klausel der Abfrage verwendet werden.

Zu den räumlichen Operatoren gehören die Bounding-Box-Operatoren (von denen der am häufigsten verwendete && ist; eine vollständige Liste finden Sie unter Section 7.10.1, “Bounding-Box-Operatoren” ) und die Abstandsoperatoren, die bei Abfragen nach dem nächsten Nachbarn verwendet werden (der am häufigsten verwendete ist <->; eine vollständige Liste finden Sie unter Section 7.10.2, “Operatoren” ).

Indexgestützte Funktionen fügen der räumlichen Bedingung automatisch einen Begrenzungsrahmenoperator hinzu. Zu den indexbasierten Funktionen gehören die benannten räumlichen Beziehungsprädikate ST_Contains, ST_ContainsProperly, ST_CoveredBy, ST_Covers, ST_Crosses, ST_Intersects, ST_Overlaps, ST_Touches, ST_Within, ST_Within und ST_3DIntersects sowie die Entfernungsprädikate ST_DWithin, ST_DFullyWithin, ST_3DDFullyWithin und ST_3DDWithin ).

Funktionen wie ST_Distance und nicht verwenden Indizes, um ihren Betrieb zu optimieren. Die folgende Abfrage wäre zum Beispiel bei einer großen Tabelle ziemlich langsam:

SELECT geom
FROM geom_table
WHERE ST_Distance( geom, 'SRID=312;POINT(100000 200000)' ) < 100

Diese Abfrage wählt alle Geometrien in geom_table aus, die innerhalb von 100 Einheiten des Punktes (100000, 200000) liegen. Sie ist langsam, weil sie den Abstand zwischen jedem Punkt in der Tabelle und dem angegebenen Punkt berechnet, d. h. eine ST_Distance() Berechnung wird für jede Zeile in der Tabelle berechnet.

Die Anzahl der zu verarbeitenden Zeilen kann durch die Verwendung der indexbasierten Funktion ST_DWithin erheblich reduziert werden:

SELECT geom
FROM geom_table
WHERE ST_DWithin( geom, 'SRID=312;POINT(100000 200000)', 100 )

Diese Abfrage wählt dieselben Geometrien aus, allerdings auf effizientere Weise. Dies wird durch ST_DWithin() ermöglicht, die den && Operator intern auf einem erweiterten Begrenzungsrahmen der Abfragegeometrie verwendet. Wenn es einen räumlichen Index auf geom gibt, erkennt der Abfrageplaner, dass er den Index verwenden kann, um die Anzahl der gescannten Zeilen zu reduzieren, bevor die Entfernung berechnet wird. Der räumliche Index ermöglicht es, nur Datensätze mit Geometrien abzurufen, deren Begrenzungsrahmen die erweiterte Ausdehnung überlappen und die daher innerhalb der erforderlichen Entfernung liegen könnten. Der tatsächliche Abstand wird dann berechnet, um zu bestätigen, ob der Datensatz in die Ergebnismenge aufgenommen werden soll.

Weitere Informationen und Beispiele finden Sie im PostGIS Workshop.

5.3. Beispiele für Spatial SQL

Die Beispiele in diesem Abschnitt verwenden eine Tabelle mit linearen Straßen und eine Tabelle mit polygonalen Gemeindegrenzen. Die Definition der Tabelle bc_roads lautet:

Column    | Type              | Description
----------+-------------------+-------------------
gid       | integer           | Unique ID
name      | character varying | Road Name
geom      | geometry          | Location Geometry (Linestring)

Die Definition der Tabelle bc_municipality lautet:

Column   | Type              | Description
---------+-------------------+-------------------
gid      | integer           | Unique ID
code     | integer           | Unique ID
name     | character varying | City / Town Name
geom     | geometry          | Location Geometry (Polygon)

5.3.1.

Wie lang ist die Gesamtlänge aller Straßen, ausgedrückt in Kilometern?

Sie können diese Frage mit einem sehr einfachen SQL-Programm beantworten:

SELECT sum(ST_Length(geom))/1000 AS km_roads FROM bc_roads;

km_roads
------------------
70842.1243039643

5.3.2.

Wie groß ist die Stadt Prince George (in Hektar)?

Diese Abfrage kombiniert eine Attributbedingung (für den Gemeindenamen) mit einer räumlichen Berechnung (der Polygonfläche):

SELECT
  ST_Area(geom)/10000 AS hectares
FROM bc_municipality
WHERE name = 'PRINCE GEORGE';

hectares
------------------
32657.9103824927

5.3.3.

Welche ist die flächenmäßig größte Gemeinde der Provinz?

Diese Abfrage verwendet ein räumliches Maß als Ordnungswert. Es gibt mehrere Möglichkeiten, dieses Problem anzugehen, aber die effizienteste ist die folgende:

SELECT
  name,
  ST_Area(geom)/10000 AS hectares
FROM bc_municipality
ORDER BY hectares DESC
LIMIT 1;

name           | hectares
---------------+-----------------
TUMBLER RIDGE  | 155020.02556131

Beachten Sie, dass wir zur Beantwortung dieser Abfrage die Fläche jedes Polygons berechnen müssen. Wenn wir dies häufig tun würden, wäre es sinnvoll, der Tabelle eine Flächenspalte hinzuzufügen, die aus Leistungsgründen indiziert werden könnte. Indem wir die Ergebnisse absteigend sortieren und den PostgreSQL-Befehl "LIMIT" verwenden, können wir einfach nur den größten Wert auswählen, ohne eine Aggregatfunktion wie MAX() zu verwenden.

5.3.4.

Wie lang ist die Länge der Straßen, die vollständig in jeder Gemeinde liegen?

Dies ist ein Beispiel für eine "räumliche Verknüpfung", bei der Daten aus zwei Tabellen (mit einer Verknüpfung) unter Verwendung einer räumlichen Interaktion ("enthalten") als Verknüpfungsbedingung zusammengeführt werden (anstelle des üblichen relationalen Ansatzes der Verknüpfung über einen gemeinsamen Schlüssel):

SELECT
  m.name,
  sum(ST_Length(r.geom))/1000 as roads_km
FROM bc_roads AS r
JOIN bc_municipality AS m
  ON ST_Contains(m.geom, r.geom)
GROUP BY m.name
ORDER BY roads_km;

name                        | roads_km
----------------------------+------------------
SURREY                      | 1539.47553551242
VANCOUVER                   | 1450.33093486576
LANGLEY DISTRICT            | 833.793392535662
BURNABY                     | 773.769091404338
PRINCE GEORGE               | 694.37554369147
...

Diese Abfrage dauert eine Weile, da jede Straße in der Tabelle im Endergebnis zusammengefasst wird (etwa 250K Straßen für die Beispieltabelle). Bei kleineren Datensätzen (mehrere tausend Datensätze auf mehrere hundert) kann die Antwort sehr schnell sein.

5.3.5.

Erstellen Sie eine neue Tabelle mit allen Straßen innerhalb der Stadt Prince George.

Dies ist ein Beispiel für eine "Überlagerung", die zwei Tabellen aufnimmt und eine neue Tabelle aus räumlich beschnittenen oder geschnittenen Ergebnisgrößen ausgibt. Anders als bei der oben gezeigten "räumlichen Verknüpfung" werden bei dieser Abfrage neue Geometrien erstellt. Ein Overlay ist eine Art "Turbo" für räumliche Verknüpfungen und eignet sich für genauere Analysen:

CREATE TABLE pg_roads as
SELECT
  ST_Intersection(r.geom, m.geom) AS intersection_geom,
  ST_Length(r.geom) AS rd_orig_length,
  r.*
FROM bc_roads AS r
JOIN bc_municipality AS m
  ON ST_Intersects(r.geom, m.geom)
WHERE
  m.name = 'PRINCE GEORGE';

5.3.6.

Wie lang ist die "Douglas St" in Victoria in Kilometern?

SELECT
  sum(ST_Length(r.geom))/1000 AS kilometers
FROM bc_roads r
JOIN bc_municipality m
  ON ST_Intersects(m.geom, r.geom
WHERE
  r.name = 'Douglas St'
  AND m.name = 'VICTORIA';

kilometers
------------------
4.89151904172838

5.3.7.

Welches ist das größte Gemeindepolygon, das ein Loch hat?

SELECT gid, name, ST_Area(geom) AS area
FROM bc_municipality
WHERE ST_NRings(geom) 
> 1
ORDER BY area DESC LIMIT 1;

gid  | name         | area
-----+--------------+------------------
12   | SPALLUMCHEEN | 257374619.430216