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.
Räumliche Beziehungen geben an wie zwei Geometrien miteinander interagieren. Sie sind die fundamentale Fähigkeit zum Abfragen von Geometrie.
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:
Die Begrenzung einer Geometrie ist die Menge der Geometrien der nächstniedrigeren Dimension. Für POINT
s, die eine Dimension von 0 haben, ist die Begrenzung die leere Menge. Die Begrenzung eines LINESTRING
sind die beiden Endpunkte. Für POLYGON
s ist die Begrenzung das Liniennetz der äußeren und inneren Ringe.
Das Innere einer Geometrie sind die Punkte einer Geometrie, die nicht in der Begrenzung liegen. Für POINT
s ist das Innere der Punkt selbst. Das Innere eines LINESTRING
ist die Menge der Punkte zwischen den Endpunkten. Für POLYGON
s ist das Innere die Fläche innerhalb des Polygons.
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:
|
||||||||||||||||||
|
|
Von links nach rechts und von oben nach unten gelesen, wird die Kreuzungsmatrix als Textstring '212101212' dargestellt.
Weitere Informationen finden Sie unter:
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.
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 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 ' 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');
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.
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 |