How to build pipelines of search criteria to search for objects relative to other objects.
We have seen examples of indirect filters in the section about Areas and the section about Around. The filter arrangement profits from the step-by-step paradigm to refer to objects that are not necessarily contained in the visible result.
We demonstrate this with the example to show all cafés in Cologne:
area[name="Köln"]; nwr[amenity=cafe](area); out center;
At the heart of the request is the filter (area)
in line 2.
The filter decided what it accepts by the area or areas
that are selected in the set _
at that moment.
It is applied in combination with the filter [amenity=cafe]
,
i.e. we select in line 2 all objects
that are a node, way, or relation and that bear the tag amenity with value cafe
and that are situated within at least one of the in _
selected areas.
To make the implicit set _
more visible,
we can use any of the following equivalent rephrasings:
area[name="Köln"]; nwr[amenity=cafe](area._); out center;
and
area[name="Köln"]->._; nwr[amenity=cafe](area); out center;
and
area[name="Köln"]->._; nwr[amenity=cafe](area._); out center;
In all cases the area is conveyed from line 1 to line 2 by the set _
.
Sets are introduced in a section of the introduction.
We also can use a set with an arbitrarily long name:
area[name="Köln"]->.extralongname; nwr[amenity=cafe](area.extralongname); out center;
But of course it does not work if the names of the sets in the two lines are not equal:
area[name="Köln"]->.extralongname; nwr[amenity=cafe](area.extralnogname); out center;
Set names are in many situations necessary to supply multiple filters with their respective input. We can search for cafés in Münster but the Overpass API then does not know which Münster is meant. There are small towns called Münster beside the large one, and these have cafés, too:
area[name="Münster"]; nwr[amenity=cafe](area); out center;
We can overcome the problem by requesting that the café must be situated both in Münster and in North Rhine-Westphalia:
area[name="Nordrhein-Westfalen"]->.a; area[name="Münster"]->.b; nwr[amenity=cafe](area.a)(area.b); out center;
The cafés are selected in line 3:
We filter for objects of the type node, way, or relation
that carry the tag amenity=cafe
and that are situated in an area stored in a
(in fact one area, i.e. the federal state of North Rhine-Westphalia)
and that are situated in an area stored in b
(all the cities, suburbs, and towns with name Münster).
Thus, only the cafés in Münster in North Rhine-Westphalia are left.
The interaction between multiple filters and pipelining will be elaborated on further in the next section.
For the sake of completeness, we demontrate that the principle of indirect filters works for all types. We want to get all bridges over the river Alster.
We can select the river by two different approaches: first, as ways:
way[name="Alster"][waterway=river]; out geom;
We select all objects of type way
that bear the tag name
with value Alster
and the tag waterway
with value river
.
These are delivered in set _
from line 1 to line 2.
Subsequently, the content of _
is printed in line 2.
We can select the bridges over the river instead of the river as follows:
way[name="Alster"][waterway=river]; way(around:0)[bridge=yes]; out geom;
The filter (around:0)
in line 2 is here the indirect filter.
We select in line 2 all ways
that have the tag bridge with value yes
and that have a distance of 0 to the objects of the set _
.
For that purpose, we have collected in line 1 into the set _
all ways
in whose surroundings we want to find results,
i.e. the ways that have a tag name
with value Alster
and a tag waterway
with value river
.
The whole thing works as well with relations ...
relation[name="Alster"][waterway=river]; out geom;
... now the bridges:
relation[name="Alster"][waterway=river]; way(around:0)[bridge=yes]; out geom;
We have met a completely different application of pipelining in the subsections Relations and Relations on Top of Relations of section Geometries: The traditional OpenStreetMap data model accepts coordinates only on nodes, but geometry is a crucial feature of other objects as well. Thus in the traditional model, ways and relations must be accompanied by their auxiliary nodes.
We explain the aspects of pipelining with an example: The tube line Waterloo & City in London can be obtained as follows:
rel[ref="Waterloo & City"]; out geom;
Then we employ an extended data model that is not supported by all downstream tools. If we instead use the traditional degree of detail out for printing, then we do not see any result on the map:
rel[ref="Waterloo & City"]; out;
The relation is after the output statement in line 2 still in the set _
.
Thus, we can collect the ways and nodes
by combining an union statement with pipelining.
The union statement is introduced in the following section.
rel[ref="Waterloo & City"]; out; ( way(r); node(w); ); out skel;
Set _
contains the relations before line 3 like mentioned above.
Lines 3 to 6 constitute the union statement.
Line 4 thus is executed next after line 2 and gets the relations as input.
The statement selects ways that match the filter (r)
,
i.e. ways that are referenced by one or more relations from the input set.
It replaces the content of the set _
with its result.
According to its semantics, union keeps a copy of this result for its own result.
The statement node(w)
in line 5 thus sees in set _
the ways from line 4.
It selects nodes that match the filter (w)
,
i.e. are referenced by one or more ways from its input, the ways found in line 4.
It again replaces the set _
with its own result,
but union subsequently anyway replaces that set again.
The union statement writes as result of line 6 the union of the results it has seen. Thus we get all ways that are referenced by the relations from line 2 and all nodes that are referenced by these ways.
Relations can have nodes as immediate members and these relations do have such members. One can see this in the Data tab or per request:
rel[ref="Waterloo & City"]; node(r); out;
This way we replace in the set _
in line 2 the relations by the referenced nodes.
Then we have in line 3 these nodes available to print them,
but we need the relations again to get the referenced ways.
Can we avoid the double query?
Yes, with named sets:
rel[ref="Waterloo & City"]; out; ( node(r)->.directly_referenced_by_the_relations; way(r); node(w); ); out skel;
In detail:
_
contains all relations
that have a tag ref
with value Waterloo & City
._
still contains the relations.(r)
operates on the content of set _
, i.e. the relations from line 1.
The statement thus puts into the set directly_referenced_by_the_relations
the nodes
that have been referenced by one or more relations.
The statement union keeps a copy of the result.
Otherwise, we are not interested in this result.
We rather want to keep the statement from overwriting the set _
.(r)
operates on the content of set _
,
and these are still the relations from line 1, because line 4 has not overwritten them.
Now the set _
is overwritten with the ways that are referenced by the relations.
The statement union keeps a copy of this result, too.(w)
uses again the set _
as input.
These are now the in line 5 written ways.
Thus set _
now consists of the nodes referenced by the ways from the previous content of set _
.
The statement union keeps a copy of this result._
._
is printed.Because this is a very frequent task, there is a shortcut for it:
rel[ref="Waterloo & City"]; out; >; out skel;
Lines 1 and 2 work as before,
and line 4 works like line 8 in the example before.
The chevron in line 3 has as semantics
that it selects the ways and nodes
that are directly or indirectly referenced by relations from its input set, here the set _
,
and writes them into the set _
.
Finally, some downstream tools rely on the fixed order in the file: they need all nodes first, then all ways, and then in the end all relations.
One can alter our request here by moving the initial statement into the union block:
( rel[ref="Waterloo & City"]; node(r)->.direkt_von_den_relations_referenziert; way(r); node(w); ); out;
Similarly with the chevron:
( rel[ref="Waterloo & City"]; >; ); out;
...
...
next: Combining by And and Or