PLZ als Geodaten und Verwendung der Straßen in Adressverwaltungen?

Ach so - Nur um erstmal die Centroiden der Postal Codes zu bekommen. osm2pgsql in die Datenbank und dann sowas:


osm=#select  osm_id,
        tags->'postal_code' postal_code,
        ST_AsText(ST_Centroid(way))
from    planet_osm_polygon
where   boundary = 'postal_code'
limit   10;
  osm_id  | postal_code |                st_astext                 
----------+-------------+------------------------------------------
 -1842460 | 41061       | POINT(6.4198451955414 51.2014935589633)
 -1842461 | 41063       | POINT(6.42718800202347 51.2113150947021)
 -1842461 | 41063       | POINT(6.44515095684154 51.2023226972125)
 -1842463 | 41066       | POINT(6.46961173755555 51.2269004927404)
 -1842276 | 41747       | POINT(6.38386400958313 51.2530904266623)
 -1842277 | 41748       | POINT(6.40642672016811 51.246710144313)
 -1842277 | 41748       | POINT(6.40762902630301 51.2422116271818)
 -1842277 | 41748       | POINT(6.39798594734734 51.2741709487333)
 -1842276 | 41747       | POINT(6.40231532045897 51.2749698730391)
 -1842278 | 41749       | POINT(6.36458035836856 51.2925325378324)

Hier das ganze für Fußgänger, sprich Overpass Nutzer:
http://overpass-turbo.eu/s/Vgd

[out:csv(note,postal_code,::lat,::lon)];
{{geocodeArea:Stuttgart}}->.searchArea;
relation[boundary=postal_code](area.searchArea);
out center;

Mit dem Ergebnis:

note	postal_code	@lat	@lon
73733 Esslingen am Neckar	73733	48.7513755	9.2812426
70599 Stuttgart	70599	48.7182183	9.2061016
70619 Stuttgart	70619	48.7420638	9.2190539
70435 Stuttgart	70435	48.8314290	9.1612667
70186 Stuttgart	70186	48.7732441	9.2101853
70563 Stuttgart	70563	48.7293152	9.1052105
70327 Stuttgart	70327	48.7786991	9.2564133
70329 Stuttgart	70329	48.7644219	9.2603705
70184 Stuttgart	70184	48.7667884	9.2004928
70499 Stuttgart	70499	48.8084152	9.1087768
70192 Stuttgart	70192	48.7977798	9.1617002
70173 Stuttgart	70173	48.7814843	9.1792174
70174 Stuttgart	70174	48.7821374	9.1696252
70191 Stuttgart	70191	48.7986482	9.1885370
70597 Stuttgart	70597	48.7450885	9.1675938
70378 Stuttgart	70378	48.8424017	9.2241147
70569 Stuttgart	70569	48.7445386	9.0898217
70199 Stuttgart	70199	48.7572559	9.1450592
70376 Stuttgart	70376	48.8182678	9.2034145
70182 Stuttgart	70182	48.7767720	9.1843825
70469 Stuttgart	70469	48.8061103	9.1552646
70197 Stuttgart	70197	48.7743598	9.1181928
70180 Stuttgart	70180	48.7627264	9.1738045
70190 Stuttgart	70190	48.7900939	9.2030421
70439 Stuttgart	70439	48.8470818	9.1549322
70567 Stuttgart	70567	48.7219413	9.1567310
70374 Stuttgart	70374	48.8108180	9.2394061
70188 Stuttgart	70188	48.7861429	9.2121972
70565 Stuttgart	70565	48.7171010	9.1276196
70195 Stuttgart	70195	48.7857855	9.1265903
70372 Stuttgart	70372	48.7995256	9.2253698
70178 Stuttgart	70178	48.7683548	9.1678679
70193 Stuttgart	70193	48.7826907	9.1469105
70176 Stuttgart	70176	48.7777194	9.1625448
70437 Stuttgart	70437	48.8367251	9.1961017

Wenn man die erste Zeile entfernt, erhält man die Kartenansicht.

Danke,
das PLZ => Geodaten gibt es auch hier schon fertig aufgelöst: https://github.com/WZBSocialScienceCenter/plz_geocoord/blob/master/plz_geocoord.csv, oder in diesem Projekt: https://github.com/yetzt/postleitzahlen - oder hier die Gebiete: https://github.com/tdudek/de-plz-geojson/blob/master/plz-5stellig.geojson

Dann hätte man nur noch die Schwierigkeit, die Straßen, die im Umkreis liegen, zu selektieren: geht das dann auch via Postgis (https://de.wikipedia.org/wiki/PostGIS)?

Gruß,
Christoph

Habe jetzt einen analogen Löungsansatz gefunden (hier geht es zwar um Flurstücke anstatt um Straßen, die im 200m Umkreis eines geplanten Windrades gesucht werden), es sollte bei PostGIS beispielsweise so gehen:


SELECT  wkb_geometry, flurstueckskennzeichen
FROM ax_flurstueck
WHERE ST_Distance( ST_GeomFromText(  'POINT(353937.74 5531106.746)',  25832 ),  wkb_geometry) <= 200 ;

=> https://wiki.postgresql.org/images/7/7d/2011-11-11_pg.conf.de_darf_ich_vorstellen_postgis_aemde.pdf
==> ST_Distance ist also meine gesuchte Funktion => https://postgis.net/docs/ST_Distance.html

Danke für alle hilfreichen Hinweise.

Gruß,
Christoph

Hallo,

Besser, da es vorhandene räumliche Indexe auf der Geometriespalte nutzt:


SELECT  wkb_geometry, flurstueckskennzeichen
FROM ax_flurstueck
WHERE ST_DWithIn( ST_GeomFromText(  'POINT(353937.74 5531106.746)',  25832 ),  wkb_geometry, 200);

Siehe auch https://postgis.net/2013/08/26/tip_ST_DWithin/

Viele Grüße

Michael, der sich keine ineffizienten Datenbankabfragen leisten kann, wenn es immer gleich um Gigabytes an Daten geht

Das funktioniert so nicht, schonmal mindestens nicht in Deutschland.
PLZ können mehrere Gemeinden umspannen und dadurch Straßennamen mehrmals enthalten.
Es gibt z.B. Schulstraße 37127 Dransfeld (OT Varmissen) und Schulstraße 37127 Scheden.
Besser ist:

  1. “select” alle Straßen innerhalb der umschließenden admin_level=8, z.B. way[highway](area.YourTown); in overpass,
  2. dann Levenshtein oder sonstige Korrelationsfaktoren berechnen (ist sogar unabhängig von der Query und könnte man aus ner pregenerierten Tabelle ziehen)
  3. Vorschläge präsentieren.

Mir ging es nicht um eine exakte Ermittlung aller Straßen in einem PLZ Gebiet, sondern nur um Vorschläge zur Rechtschreibkorrektur bei offensichtlichen Tippfehlern.
Deshalb würde ich um das geometrische Zentrum (nach @Nakaner - danke für den Hinweis) mit ST_DWithIn im Kreis mit einer großzügigen Distanz nach relevanten Straßen als Vorschläge suchen, die der Benutzer in der Adressverwaltung dann übernehmen kann oder auch nicht. Um es vollautomatisch (ohne Benutzereingriff exakt) zu lösen, dürfte man ja programmiertechnisch nur innerhalb der PLZ Grenzen nach Straßen suchen, was den Algorithmus kompliziert und langsam machen würde.
Da ich ein Anfänger im Projekt OSM bin, sagt mir der Satz:
“select” alle Straßen innerhalb der umschließenden admin_level=8, z.B. way[highway](area.YourTown); in overpass,
(noch?) leider gar nichts. Kannst du das näher ausführen?
Die Levenshtein Distanz ist mir wieder klar, damit ist das gemeint: https://de.wikipedia.org/wiki/Levenshtein-Distanz

Viele Grüße,
Christoph

Es geht schlicht um die (mathematische) Menge aller Straßennamen in der gewählten Gemeinde. Die ergibt sich widerrum einfach aus der Menge aller Straßensegmente, die in der Gemeinde liegen. Die Gemeinde selber liegt als Area vor. Und mit dem Wissen baust du dir dann dein SQL-Statement zusammen, mit SELECT und ST_DWithin und was-auch-immer.

Die meisten Anwender halten aber keinen PostGIS-DB-Klon lokal vor. Daher wird oft die Overpass-DB (remote) abgefragt, und das mit Overpass-QL. Die Select-Statements sehen dort gänzlich anders aus, auch weil es, anders als SQL, eine Art imperative Sprache ist.

Was wahrscheinlich die beste Lösung wäre: wenn man doch versuchen würde im PLZ Gebiet möglichst exakt die Strassen zu ermitteln und die Ergebnisse dann in eine Tabelle zu speichern. Die Adressverwaltung könnte dann performant über Indexe auf diese Tabelle zugreifen (und bräuchte kein PostGIS / Overpass-QL, da sie über die PLZ einfach die relevanten Strassen filtern und vorschlagen könnte). Dann wäre die Laufzeit egal, da man die Strassenaktualisierung von OSM => PLZ/Strassentabelle nur einmal im Vierteljahr laufen lassen müsste (die Strassen ändern sich ja nicht täglich ;-)).

Das wäre dann die zweite, schwierigere Aufgabenstellung zur ersten Umkreissuche Lösung:
==> Suche alle Strassen innerhalb eines PLZ Gebietes.
Wie könnte man dies bewerkstelligen? Gibt es da auch schon fertige Befehle dazu, wie bei der Umkreissuche mit ST_DWithIn, oder muss man da selbst erst einen Algorithmus entwickeln?

Viele Grüße,
Christoph

In https://forum.openstreetmap.org/viewtopic.php?id=20839 ist schon erklärt, wie man so eine Liste mit overpass generiert. Da jeder Straßenschnipsel einzeln aufgeführt wird, muß man die Roh-Liste beispielsweise mit den üblichen Kommandozeilentools sortieren und die Duplikate rausfischen.

Gruß,

Baßtölpel

Nach: https://wiki.openstreetmap.org/wiki/DE:Overpass_API/Beispielsammlung#Stra.C3.9Fenliste und: https://wiki.openstreetmap.org/wiki/DE:Overpass_API/Beispielsammlung#Abweichende_addr:postcode.3DXXXXX_Tags_innerhalb_einer_Grenzrelation_mit_postalcode.3C.3EXXXXX sollte es eigentlich so funktionieren:


[out:csv(name;false)];
area[postal_code="XXXXX"];
way(area)[highway][name];
out;

XXXXX => enthält dann die PLZ. Oder sollte ich lieber:


["addr:postcode"="XXXXX"]

verwenden? Was ist denn der Unterschied zwischen postal_code und postcode?

Oder gar?


area[postal_code="XXXXX"]->.a;(node(area.a)["addr:postcode"]["addr:postcode"="XXXXX"];

Viele Grüße,
Christoph

postal_code=“XXXXX” hängt an dem Gebiet mit der PLZ=XXXXX,
wie z.B. https://www.openstreetmap.org/relation/1226643
Dabei ist die Abdeckung in DE (ziemlich) vollständig.

addr:postcode hängt in der Regel an einem Gebäude, event. auch an einem Grundstück.
https://www.openstreetmap.org/way/39973424
Straßen haben dagegen kein tag addr:postcode.
In DE fehlen noch Millionen von Adressen und damit auch das addr:postcode daran.

@fx99: Vielen Dank für den Hinweis, dann nehme ich postal_code.

Auszug aus DE:Overpass API Wiki:

Download großer Mengen von Daten
Da die Größe des Ergebnis einer Overpass API Abfrage erst dann bekannt ist, wenn der Download abgeschlossen ist, ist es nicht möglich, während des Downloads eine Dauer für diesen Download abzuschätzen. Auch benötigt die Overpass API länger dafür, die Daten zu generieren und zu downloaden, als man bräuchte, um einfach alle Daten der selben Region statisch zu downloaden. Daher ist es besser, ein Planet file zu downloaden, wenn man Regionen in Ländergröße mit (fast) allen Daten haben will. Die Overpass API ist dagegen dann sehr nützlich, wenn man nur eine Auswahl von Daten einer bestimmten Region haben möchte.

=> https://wiki.openstreetmap.org/wiki/DE:Overpass_API#Einschr.C3.A4nkungen

==> Bekomme ich da ein Problem, wenn ich alle Straßen ganz Deutschlands herunterladen will? PostGIS ist halt schwierig zu installieren - mit der Overpass API wäre es deutlich einfacher.

Viele Grüße,
Christoph

Wenn Du die geschätzt 10.000 Abfragen am Stück laufen lässt, bekommst Du wahrscheinlich Probleme mit der Quota.
Aber zeitlich verteilte Abfragen auf den diversen Overpass Servern könnte gehen.

Spätestens, wenn es Richtung Europa ginge (FR / CH / AU wären z. B. auch interessant), wäre dieses wohl unumgänglich: Overpass API/Installation als Clon => https://wiki.openstreetmap.org/wiki/Overpass_API/Installation
Oder sieht jemand noch einen anderen Weg?

Wenn Du wieder zu Deinem ersten Post zurückgehst und nicht das exakte PLZ Gebiet willst,
sondern nur z.B. eine **rechteckige **Annäherung, sprich bounding box, könntest Du das ganze mit heruntergeladenen Daten
und **osmconvert ** https://wiki.openstreetmap.org/wiki/Osmconvert plus
**osmfilter **https://wiki.openstreetmap.org/wiki/Osmfilter machen.

Um die Nachverarbeitung, jeden Straßennamen in einem Gebiet nur einmal und sortiert zu haben, kommst Du auch mit overpass nicht herum.

ACK, deshalb habe ich mir nun anhand der obigen Anleitung die overpass API installiert - die beeindruckt mich doch sehr ob ihrer Funktionalität. Das funktioniert nun gut, ich kann nun z. B. via SSH und Python (https://python-overpy.readthedocs.io/en/latest/introduction.html) auf die API zugreifen, denn Python scheint mir ohne viel Overhead elegant auf die API zuzugreifen und dann kann ich auch soviele Abfagen pro Sekunde machen, wie das System hergibt - und ich habe gleich die ganze Welt installiert. :slight_smile:

Danke für alle Hinweise, nun sollte sich mein Problem vollends lösen lassen. :slight_smile:

Gruß,
Christoph

Theoretisch ja, praktisch naja :wink:

=> Bekomme in meiner lokalen Installation die folgende Fehlermeldung, wenn ich z. B. absetze:

[out:csv("name";false)];area["postal_code"="75382"];way["highway"]["name"](area);out;

runtime error: open64: 2 No such file or directory /lib/osm-db/area_tags_global.bin File_Blocks::File_Blocks::1

=> Setze ich das Kommando jedoch im Online Formular hier: http://overpass-api.de/query_form.html ab, tut jedoch alles, die stimmt also.

=> Wenn ich in meiner lokalen Installation die offizielle Beispielabfrage absetze, dann tut es auch:

<query type="node"><bbox-query n="51.0" s="50.9" w="6.9" e="7.0"/><has-kv k="amenity" v="pub"/></query><print/>

==> Da fehlt in meiner Installation doch die Datei /lib/osm-db/area_tags_global.bin, wie kann ich die erzeugen, was habe ich da falsch gemacht?

Ich hatte dieses Kommando abgesetzt, um die Datenbank zu füllen, war das nicht ausreichend (siehe: https://wiki.openstreetmap.org/wiki/Overpass_API/Installation#Populating_the_DB)?

./download_clone.sh --db-dir=database_dir --source=http://dev.overpass-api.de/api_drolbr/ --meta=no

Viele Grüße,
Christoph

Hi ihr,

… mein Post ist zwar nicht mehr ganz so taufrisch ;-), aber mit…

… konnte ich nun die Straßen abrufen, aber wie kann ich sie z. B. jeweils auf D / A / CH eingrenzen? D.h. also: wie kann man zusätzlich das Land abfragen?

=> Das ist nun noch mein Problem.

==> Das andere Installationsproblem habe ich einfach so umgangen, dass ich vor jeder Abfrage auf einen öffentlichen Server eine künstliche Denkpause von 300ms eingebaut habe, um nicht Gefahr zu laufen, unter die Rurik DoS (Denial of Service) zu fallen. Das hat bislang gut funktioniert, habe inzwischen ca. 20.000 Abfragen laufen lassen (allerdings nicht am Stück).

Viele Grüße,
Christoph

Hi again,

im dritten Anlauf hat ChatGPT das zustande gebracht:

[out:csv(name;false)];
area[postal_code="XXXXX"]->.a;
(
  area.a -> .b;
  area.b["ISO3166-1"="DE"];
);
way(area.b)[highway][name];
out;

Mit dieser Begründung:

In dieser überarbeiteten Version wird die Bereichsabfrage für die Postleitzahl durchgeführt und in der Variable .a gespeichert. Dann wird eine weitere Abfrage durchgeführt, um die Grenze dieser Postleitzahl abzurufen und in .b zu speichern. Anschließend wird die ISO3166-1-Kennzeichnung auf .b angewendet, um die Gebiete von Deutschland und Österreich zu selektieren. Schließlich werden die Straßen in diesen Gebieten abgefragt und als CSV ausgegeben.

Bitte ersetze “XXXXX” durch die gewünschte Postleitzahl oder entferne es, wenn du nach allen Straßen in dem Bereich suchen möchtest.

=> Habe es eben mit overpass-turbo getestet und es scheint genau das zu tun, was es tun soll, denn nun kamen nur noch deutsche Straßen, wenn ich z. B. 01561 für XXXXX eingesetzt habe.

Passt das so?

Viele Grüße,
Christoph