Wie man mehrere Suchkriterien verkettet, so dass man nach Objekten relativ zu anderen Objekten suchen kann.
Beispiele für indirekte Filter haben wir bereits bei Areas und Around gesehen. Es kann per Aneinanderreihung auch auf Objekte Bezug genommen werden, die gar nicht im Endergebnis enthalten sind.
Wir schauen uns das am Beispiel an, alle Cafés in Köln zu finden:
area[name="Köln"]; nwr[amenity=cafe](area); out center;
Zentral ist hier der Filter (area)
in Zeile 2.
Der Filter filtert auf die Fläche oder Flächen,
die er im Set _
vorfindet.
Er wirkt zusammen mit dem Filter [amenity=cafe]
,
d.h. wir suchen in Zeile 2 alle Objekte,
die Node, Way oder Relation sind (nwr) und das Tag amenity mit Wert cafe tragen
und innerhalb der in _
hinterlegten Flächen liegen.
Wir können also die obige Abfrage auch umformulieren und erhalten das exakt gleiche Ergebnis:
area[name="Köln"]; nwr[amenity=cafe](area._); out center;
und
area[name="Köln"]->._; nwr[amenity=cafe](area); out center;
und
area[name="Köln"]->._; nwr[amenity=cafe](area._); out center;
In allen Fällen wird die Fläche von Zeile 1 nach Zeile 2 durch das Set _
vermittelt.
Sets werden in einem Abschnitt der Einleitung eingeführt.
Wir können auch ein Set mit beliebigem Namen verwenden:
area[name="Köln"]->.ganzlangername; nwr[amenity=cafe](area.ganzlangername); out center;
Es funktioniert allerdings nicht, wenn der Name der Sets in beiden Zeilen nicht übereinstimmt:
area[name="Köln"]->.ganzlangername; nwr[amenity=cafe](area.ganzlangrname); out center;
Nützlich werden Set-Namen dann, wenn man mehrere Filter ansteuern möchte. Wir können z.B. zwar nach Cafés in Münster suchen, aber die Overpass API weiß dann nicht, welches Münster wir meinen, da es außer der großen Stadt auch viele kleinere Orte mit dem Namen gibt und diese auch Cafés haben:
area[name="Münster"]; nwr[amenity=cafe](area); out center;
Wir können aber verlangen, dass das Café sowohl in Münster als auch in Nordrhein-Westfalen liegen muss:
area[name="Nordrhein-Westfalen"]->.a; area[name="Münster"]->.b; nwr[amenity=cafe](area.a)(area.b); out center;
Die Cafés werden in Zeile 3 selektiert:
Wir wählen Objekte vom Typ Node, Way oder Relation,
die das Tag amenity=cafe
tragen
und die sowohl in einer der in a
gespeicherten Flächen (nur 1 Fläche, nämlich das Bundesland Nordrhein-Westfalen)
als auch in einer der in b
gespeicherten Flächen (alle Städte, Stadtteile und Dörfer mit Namen Münster) liegen.
Das sind nur nur noch die Cafés in Münster in Westfalen.
Das Zusammenspiel zwischen mehreren Filtern und Verkettung wird im nächsten Abschnitt vertieft.
Der Vollständigkeit halber sei darauf hingewiesen, dass das Prinzip der indirekten Filter für alle Typen existiert. Wir wollen alle Brücken über den Fluss Alster finden.
Den Fluss Alster können wir gleich auf zwei verschiedene Weisen finden, zunächst per Way:
way[name="Alster"][waterway=river]; out geom;
Wir suchen dazu nach alle Objekten vom Typ Way,
die das Tag name mit Wert Alster und das Tag waterway mit Wert river tragen.
Diese stehen nach Zeile 1 im Set _
und werden von dort in Zeile 2 ausgegeben.
Die Brücken anstatt des Flusses finden wir wie folgt:
way[name="Alster"][waterway=river]; way(around:0)[bridge=yes]; out geom;
Hier ist (around:0)
in Zeile 2 der indirekte Filter.
Wir suchen in Zeile 2 alle Ways,
die das Tag bridge mit Wert yes haben
und die einen Abstand 0 zu den Objekten aus dem Set _
haben.
Das Set _
haben wir dazu in Zeile 1 mit den Ways befüllt, in deren Umkreis wir suchen wollen,
und zwar alle Ways, die ein Tag name
mit Wert Alster
und ein Tag waterway
mit Wert river
haben.
Das ganze funktioniert auch mit Relations ...
relation[name="Alster"][waterway=river]; out geom;
... nun mit Brücken:
relation[name="Alster"][waterway=river]; way(around:0)[bridge=yes]; out geom;
Einer völlig anderen Anwendung für Verkettung sind wir in Abschnitten Relationen und Relationen auf Relationen in Geometrien begegnet: Da das traditionelle OSM-Datenmodell Koordinaten nur auf Nodes zulässt, aber auch an den anderen Objekten ihre Geometrie interessant ist, müssen im traditionellen OSM-Datenmodell Ways und Relations um die jeweiligen Hilfsobjekte ergänzt werden.
Die Verkettungsaspekte erklären wir an einem Beispiel: Die U-Bahn-Linie Waterloo & City in London können wir zwar wie folgt bekommen:
rel[ref="Waterloo & City"]; out geom;
Dann gebrauchen wir aber ein erweitertes Datenmodell, das nicht alle Anwendungen unterstützen. Wenn wir dagegen den traditionellen Detailgrad out zur Ausgabe nutzen, so sehen wir gar nichts:
rel[ref="Waterloo & City"]; out;
Die Relation steht nach der Ausgabe in Zeile 2 aber noch immer im Set _
.
Wir können daher die zugehörigen Ways und Nodes sammeln,
indem wir das im folgenden Abschnitt erläuterte Union mit Verkettung kombinieren:
rel[ref="Waterloo & City"]; out; ( way(r); node(w); ); out skel;
Vor Zeile 3 stehen im Set _
wie schon erwähnt die gefundenen Relationen.
Zeilen 3 bis 6 sind das Union.
Zeile 4 way(r)
ist daher die nächste nach Zeile 2 ausgeführte Zeile und erhält die Relationen als Eingabe.
Es sucht nach Ways, die dem Filter (r)
genügen,
d.h. von einer oder mehreren Relations in der Eingabe referenziert werden.
Als Ergebnis schreibt es diese Ways nun in das Set _
.
Das Block-Statement Union behält gemäß seiner Semantik eine Kopie davon für sein Ergebnis.
Zeile 5 node(w)
findet also die Ways aus Zeile 4 als Eingabe im Set _
vor.
Es sucht nach Nodes, die dem Filter (w)
genügen,
d.h. von einer oder mehreren Ways in der Eingabe referenziert werden.
Als Ergebnis schreibt es diese Ways zwar in das Set _
,
aber Union ersetzt das Set ohnehin durch sein eigenes Ergebnis.
Als Ergebnis von Zeile 6 schreibt Union in das Set _
die Vereinigung der Ergebnisse,
die es gesehen hat.
Wir erhalten also alle Ways, die von den Relationen referenziert worden sind
und alle Nodes, die von diesen Ways referenziert worden sind.
Allerdings können Relationen auch Nodes direkt als Member haben, und diese Relationen haben dies auch; man sieht dies im Daten-Tab oder per Abfrage:
rel[ref="Waterloo & City"]; node(r); out;
Auf diesem Weg ersetzen wir im Set _
in Zeile 2 die Relations durch die referenzierten Nodes.
Dann haben wir zwar für die Ausgabe in Zeile 3 diese Nodes zur Verfügung,
bräuchten aber die Relations erneut,
um die referenzierten Ways zu erhalten.
Können wir die Doppelsuche vermeiden?
Ja, mit benannten Sets:
rel[ref="Waterloo & City"]; out; ( node(r)->.direkt_von_den_relations_referenziert; way(r); node(w); ); out skel;
Im Detail:
_
alle Relations,
die ein Tag ref
mit Wert Waterloo & City
haben._
stehen nach wie vor die Relations.(r)
der Inhalt von Set _
genutzt, nämlich die Relations aus Zeile 1.
Damit werden neu im Set direkt_von_den_relations_referenziert
diejenigen Nodes abgelegt,
die von einer der Relations referenziert werden.
Union behält eine Kopie des Ergebnisses zurück.
Ansonsten sind wir nicht an dem Ergebnis interessiert,
sondern wollen nur das Statement davon abhalten, das Set _
zu überschreiben.(r)
wiederum der Inhalt von Set _
genutzt,
und dies sind noch immer die Relations, da wir diese nicht überschrieben haben.
Im Set _
sind nun die Ways abgelegt, die von den Relations referenziert werden.
Union behält eine Kopie des Ergebnisses zurück.(w)
wiederum der Inhalt von Set _
genutzt.
Dies sind nun die in Zeile 5 geschriebenen Ways.
Also werden im Set _
nun die von diesen Ways referenzierten Nodes abgelegt.
Union behält eine Kopie des Ergebnisses zurück._
._
ausgegeben.Da dies ein sehr häufiges Problem ist, gibt es für genau diese Aufgabe auch eine Abkürzung:
rel[ref="Waterloo & City"]; out; >; out skel;
Zeilen 1 und 2 arbeiten exakt wie vorher,
und Zeile 4 arbeitet exakt wie Zeile 8 vorher:
Denn der Pfeil in Zeile 3 hat als Semantik,
dass er zu Relations im Set _
die direkt und indirekt referenzierten Ways und Nodes findet
und ins Set _
ausgibt.
Nun sind zuletzt noch einige Programme überfordert, wenn die Reihenfolge in der Datei nicht exakt alle Nodes, dann alle Ways, dann zuletzt alle Relations ist.
Für den detaillierten Ansatz erreicht man dies, indem die initiale Anfrage in den Union-Block verschiebt:
( rel[ref="Waterloo & City"]; node(r)->.direkt_von_den_relations_referenziert; way(r); node(w); ); out;
Ebenso mit dem Pfeil:
( rel[ref="Waterloo & City"]; >; ); out;
...
...
weiter: Und- und Oder-Verknüpfung