Sets in Overpass turbo.

Hi,

could someone explain how Overpass turbo handles it’s sets?

If I use a set as input set - is it emptied?

See, I have got this query created by @Teiron:


//This query gets residentials and their buildings within bbox.
[out:json][timeout:25];
// Having below query used two times isn't an error. This was done purposefully because nodes have null names which mess with results.
(
  way["highway"="residential"]({{bbox}});
  >;
)-> .highways; //nodeful

(
  way["highway"="residential"]({{bbox}});
); //nodeless

()->.container; //initialize empty set

foreach(
    (._;) -> .a; //get node free highways
  (
  	way["building"]
    (if: t["addr:street"] == a.set(t["name"]))
    ({{bbox}});
  	relation["building"]
    (if: t["addr:street"] == a.set(t["name"]))
    ({{bbox}});
    )-> .buildings;
  
  (.buildings;.buildings >;)->.buildings; //get nodes for buildings geometry;
  
  (.buildings; .container;)->.container; //append to container
);

(.container;.highways;)-> .result; //merge buildings and highways

.result out;

And I don’t understand, why the beginning can’t be just:


(
  way["highway"="residential"]["name"]({{bbox}});
); //nodeless

(._; ._ >;)->.highways;

…instead of repeating the query

way["highway"="residential"]["name"]({{bbox}});

?

When I try the second way then the foreach loop seems to get an empty set of highways, as if

(._; ._ >;)->.highways;

emptied the default set.

I did some streamlining to your query… some of your issues are caused by how the default inputset ._ is used and overwritten. To make things clearer, I switched to named inputsets where possible.

So, here’s a list of all changes:

  • use a global bounding box instead of repeatingly adding ({{bbox}})

  • Named inputsets are empty by default, no need to initialize them

  • move the building query outside the foreach loop, store it in an inputset and use the inputset inside the foreach loop instead

  • added [“addr:street”] restriction to building query, assuming you’re only interested in buildings with such a tag (performance)

  • avoid unnecessary sets where possible

  • add [name] restriction to highway=residential (performance)

  • use named inputsets for foreach statement, dont’t realy on ._ , i.e. no need to fiddle around with ._ and store it in a named inputset only inside the loop.

  • resolving ways to nodes is done only towards the end of the query (it’s not needed earlier than that)

And the updated query:


//This query gets residentials and their buildings within bbox.

[out:json][timeout:25]
[bbox:{{bbox}}];    // set global bounding box

// retrieve all residential ways with name
way[highway=residential][name] ->.highways;

// retreve buildings outside the foreach loop (performance)
( way[building]["addr:street"];
  rel[building]["addr:street"]; 
) -> .allbuildings;

foreach.highways -> .a (

  // find buildings where addr:street matches highway name
  (
    way.allbuildings       (if: t["addr:street"] == a.set(t["name"]));
    relation.allbuildings  (if: t["addr:street"] == a.set(t["name"]));
  )-> .buildings;
  
  // collect building
  (.result_buildings; .buildings; )->.result_buildings;  
);

// resolve ways to nodes
( ( .result_buildings; .highways;); >;);

// return result
out;

overpass turbo link: http://overpass-turbo.eu/s/pZp

Thanks, that solves the problem of repeating a query and it is much faster that way.

But I’d like to know: can I reuse input set or is it emptied when used once?
Is there some document describing how exactly sets are handled?

Also, do you have an idea why your query returns some nodes with highway=crossing as separate results?

You can think of an inputset (named or .) as some kind of global variable, which is valid for the whole query. Once you assign some data to it, it will keep it for the rest of the query. If you assign some other data to an inputset, the previous contents will be replaced. Note that some queries / statements will change the contents of the default inputset ".", which can be confusing at times. If you’re unsure, use named inputsets instead, like in my example.

If it’s not mentioned in the Overpass QL documentation there’s probably no dedicated document. Usually you would find the respective information for each statement, like union, or foreach.

Yes, that’s due to the way how ways are resolved to nodes. The approach I used is more suitable for editing in JOSM, as it includes all data (out meta; instead of out; would still be better). If you don’t want to this level of detail, you could use either http://overpass-turbo.eu/s/q0a or http://overpass-turbo.eu/s/q0f

Well, that was my intuition at the beginning (one of things I tried before posting here was switching to .nodeless set instead of ._).

OK, so just to see if I understand it correctly, I’ve changed the original query to:
http://overpass-turbo.eu/s/q42
It uses named set .nodeless instead of ._ , does not initiate .result set and tries to collect buildings directly into .result inside foreach loop. Could you pinpoint why this query does not return any buildings? I know your query is better, but I want to understand what I’m doing.

Rrright, so I’ll put my question in another words: do you know of an Overpass QL documentation other than:
http://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide
http://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL
http://wiki.openstreetmap.org/wiki/Overpass_turbo/MapCSS
?

What about

https://github.com/osmlab/learnoverpass

and

http://dev.overpass-api.de/blog/ ?

I think you really need to study how foreach works with regards to named inputsets and switch to something like: http://overpass-turbo.eu/s/q5E

We’ll take a look at your query and outline what’s going wrong here:


foreach(
    (.nodeless;) -> .a; //get node free highways

foreach iterates over all entries in the default set ._. At this time it contains a number residential ways, which is in fact a side effect of an earlier way"highway"=“residential”; inside a union statement.

Now, (.nodeless;) → .a; is basically just copying ALL residential ways from .nodeless to .a - that’s not really what you want, especially, as the copying occurs in every single foreach iteration. What you’re really after is to take one element from .nodeless and store it in .a.

Going further, a.set(t[“name”]) will produce a concatenated list of ALL names - check the output of this debug query: http://overpass-turbo.eu/s/q5G

Iterating over a named inputset and assigning one element per each iteration has a different syntax:


foreach .nodeless -> .a ( ... );

Well, I think I understood more from this thread alone than from ca two weeks of RTFM and experimenting. Thanks, really.

I think your first query should be put on the wiki page you have in your sig described as “Comparing tags between objects” or so. Maybe with more comments from your first post.