Overpass QL: find nodes that have any keys in addition to specified

Hi. I want to search tagged nodes that aren’t only address nodes. - e.g. POIs with an address are fine, as well as nodes without any addr:*=*.
In essence:

  • take tags of the node
  • remove addr:housenubmer, addr:street, addr:city, source:addr (etc.) from the tag list
  • if there are any tags still left - then output the node.

Is it possible in Overpass QL?

2 Likes

https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#Difference

Returns everything in the first set minus everything in the second set. It sounds like that should work for you?

It won’t. It works over whole elements (nodes, ways, relations), not tags.
Well, you could make an abomination like
node["addr:housenumber"]["addr:street"](if: count_tags()==2); node["addr:housenumber"]["addr:street"]["addr:city"](if: count_tags()==3); and subtract that, but you would need to list every possible combination. With 10 or so keys that qualify as address-related it’s a recipe for a combinatorial explosion.

For the minus set we need to exclude the addr tags but I dont think that we can use the Not exist ! parameter with regular expressions like [~“addr:”].

An other solution is to list all the expected other tags like:

  node[~"addr:"~"."]({{bbox}})->.all;
  (
  node.all[amenity]({{bbox}});
  node.all[shop]({{bbox}});
  node.all[office]({{bbox}});
  );
  out meta;

Actually knowing the length of a list I could make a regex on keys and then duplicate it, but still this is inelegant. Example for a reduced list of 3 tags addr:housenumber, addr:city, addr:street:

node[~"^(addr:housenumber|addr:city|addr:street)$"~".*"](if: count_tags()==1); node[~"^(addr:housenumber|addr:city|addr:street)$"~".*"][~"^(addr:housenumber|addr:city|addr:street)$"~".*"](if: count_tags()==2); node[~"^(addr:housenumber|addr:city|addr:street)$"~".*"][~"^(addr:housenumber|addr:city|addr:street)$"~".*"][~"^(addr:housenumber|addr:city|addr:street)$"~".*"](if: count_tags()==3);
Probably colons in regexes need escaping, haven’t tested that.

Well, that is also what I considered, such list would still be quite long and won’t cover everything.
The problem I want to solve is to check how many nodes are there that weren’t imported addresses. Making stats is quite easy afterwards.

Honestly seems I would have much more luck expressing what I want in PostgreSQL with osmosis-imported database in pgsnapshot schema. After all, hstore data type can be subtracted.

With overpass json output, you could easily import into a python script. Then, you have the choice to process in python or postgresql.

  
  [out:json];
  node[~"addr:"~"."]({{bbox}});
  out tags center;

FWIW

area[name="Wuppertal"];
(
   node(area)[~"addr:"~"."];
- node._[~"^[^a]|^a[^d]|^ad[^d]|^add[^r]"~"."]; );
out;

976 nodes that are an address only in my home municipality alone.

I meant all nodes minus address-only nodes. Though I had not really thought through how to identify address-only nodes!

Using drolbr’s code gives

node(if:count_tags()>0)({{bbox}}) -> .tagged_nodes;
(
  node({{bbox}})[~"addr:"~"."]; - node._[~"^[^a]|^a[^d]|^ad[^d]|^add[^r]"~"."];
) -> .address_nodes;
(.tagged_nodes; - .address_nodes;);
out;

This seems to do what you need? (Though it might need some more tweaking, in case you don’t want results where the only other tag is source = survey or entrance = yes)