Straße/Ort suchen

Guten Morgen,

ich würde gerne wissen, ob es möglich ist über eine Anwendung nach Straßennamen oder Orten zu suchen. z.B. Über eine Datenbankabfrage. Optimal wäre es, wenn dann als Ergebnis Koordinaten herauskommen würden, die dann weiter verarbeitet werden können.

Ich habe eine Anwendung geschrieben, die eine Mapnik Karte darstellt. Nun soll der User nach einem Straßennamen suchen und diese dann auf der Karte angezeigt bekommen.

Ich habe einen Blick auf Nominatim geworfen, nur leider benötige ich eine Offline-Lösung.

Vielen Dank schonmal für eure Hilfe.

Mit freundlichen Grüßen
mvollmer

Den einzigen Hinweis den ich geben kann:

geh mal auf help.openstreetmap.org und such dort nach geocoding …

Hallo,

ich habe mir nun ein paar Seiten zu reversed Geocoding und Nominatim durchgelesen. Doch leider konnte ich nicht den richtigen Ansatz finden um mein Problem zu lösen.

Die frage die sich mir stellt ist, ob es möglich ist ohne weiteres mit einer SQL Abfrage die Koordinaten von einer Adresse ausgeben zu lassen.

Ich habe dies versucht mit folgender Abfrage:

SELECT name,way FROM planet_roads WHERE name = 'Tischbeinstraße'

Ausgabe:

"Tischbeinstraße";"010200002031BF0D0005000000C3F528DC0D173041F6285C8FBE775941295C8F027C163041A4703D8ABA775941F6285C0FD6153041E17A146EB57759413D0AD7E3A7153041C3F5285CB47759410AD7A3B0781530415C8FC275B4775941"
"Tischbeinstraße";"010200002031BF0D000400000052B81E059C1730418FC2F538C4775941713D0A975C1730411F85EBB1C1775941000000802D1730411F85EBD1BF775941C3F528DC0D173041F6285C8FBE775941"
"Tischbeinstraße";"010200002031BF0D000500000052B81E059C1730418FC2F538C4775941D7A370FDC0173041000000A0C577594185EB5138E217304114AE4791C5775941F6285CCFFD1730417B14AEC7C4775941713D0A5729183041C3F5281CC2775941"
"Tischbeinstraße";"010200002031BF0D0009000000713D0A5729183041C3F5281CC27759410AD7A3F0EB183041E17A145EBA77594185EB51B88C193041295C8FE2B3775941666666E6C91930415C8FC285B0775941B81E85EBD319304152B81EC5AF7759418FC2F528011A3041EC51B8AEAC77594100000000401A304114AE4771A7775941AE47E1FA7E1A3041C3F5286CA1775941B81E85EBA31A3041EC51B8AE9C775941"
"Tischbeinstraße";"010200002031BF0D0008000000B81E85EBA31A3041EC51B8AE9C77594100000000491B304152B81E558877594133333373871B30413D0AD77381775941F6285C8FB31B30411F85EBD17D775941B81E856BDE1B3041CDCCCC8C7B775941295C8F823A1C30415C8FC2F573775941D7A3707DDF1C304185EB51186A77594148E17A94881D3041AE47E11A5B775941"
"Tischbeinstraße";"010200002031BF0D000300000048E17A94881D3041AE47E11A5B7759417B14AE87911D3041AE47E1AA597759413D0AD7E3981D3041AE47E10A58775941"

Jetzt müsste es doch reichen, wenn man den way(geometry) in die Lon/Lat-Koordinaten umwandelt?

Oder gehe ich das ganze hier falsch an? Ich möchte eine Möglichkeit erstellen die Nominatim ähnelt. Nur Offline und unter Windows und wen möglich nur mit SQL Abfragen.

Falls dies nicht möglich ist bzw. der falsche Weg dann würde ich als nächste Möglichkeit, den Nominatim Service unter Windows zum laufen zu bringen, in betracht ziehen.

Gruß
mvollmer

Um den “Mittelpunkt” einer Straße auszugeben reicht das da (Postgres-Datenbank im Standard-osm2pgsql-Schema mit Daten in Mercatorprojektion):

osm=> select st_astext(st_transform(st_centroid(way),4326)),highway,name from osm_roads where name='Hauptstraße' limit 4;
                st_astext                 |  highway  |    name     
------------------------------------------+-----------+-------------
 POINT(10.1793409958092 48.2243876577699) | secondary | Hauptstraße
 POINT(10.1877192211362 48.5291684950066) | secondary | Hauptstraße
 POINT(10.2075612057857 47.9751821481288) | secondary | Hauptstraße
 POINT(10.2102533454823 47.806401949148)  | secondary | Hauptstraße

“st_centroid” gibt die Mitte eines Weges aus (die nicht zwingend auf dem Weg liegt, evtl wäre Anfang oder Ende besser…), “st_transform” wandelt den Weg in die passende Projektion, “st_astext” in eine menschenlesbare Form

Nominatim sucht noch innerhalb eines passenden Polygons der Gemeindegrenze (so vorhanden, alternativ im Umkreis eines place-nodes), kennt Hausnummern, Postleitzahlenpolygone(?)… das alles nachzubilden ist möglich, aber langwierig, fürchte ich…

Grüße, Max

Hallo,

vielen Dank maxbe für deine Antwort und die ausführliche Erklärung! Wenn ich das also richtig sehe, hört es auch schon mit dem Hauptstraßenamen auf und um nach einem Ort, PLZ , einer nicht Hauptstraße, Hausnummern,… zu suchen würde viel mehr aufwand nötig sein?

oder kürzer


osm=# select (point(centroid(way))) as mittelpunkt, name from osm_roads where name='Hauptstraße' limit 4;
        mittelpunkt        |    name
---------------------------+-------------
 (7.41104965,50.9052991)   | Hauptstraße
 (12.13018855,49.12755065) | Hauptstraße
 (13.36020645,52.49035795) | Hauptstraße
 (14.5365504,51.09437065)  | Hauptstraße
(4 Zeilen)


Projektion spielt doch keine Rolle, oder?

Du kannst Dich durch die admin-boundary-Polygone hangeln. Hier hab ich mal damit gespielt, die SQL-Anfragen dazu sind verlinkt, bei Hausnummern hab ich aber die Lust verloren :wink: . Ich wollte eigentlich “Koordinate->Adresse” umwandeln, den Teil mit “Strassen suchen” kannst Dir also sparen, der Teil mit “Gemeinde suchen” und “PLZ suchen” wäre für Dich interessant.

Ich bin mir nur nicht sicher, wie flächendeckend die Polygone eingetragen sind (vermutlich reichts aber in Deutschland?). Nominatim macht dann eben Annahmen wie “liegt näher am place-node von Ort X”.

Fürs Rechnen und Suchen in der DB nicht. Im Gegenteil da ist es besser, nicht unnötig hin- und herzurechnen. Für die Ausgabe finde ichs aber schöner, das in gewohnten Längen/Breitengraden auszugeben. Bei mir sieht es ohne Umwandlung so aus:

osm=> select (point(centroid(way))) as mittelpunkt, name from osm_roads where name='Hauptstraße' limit 4;
        mittelpunkt        |    name     
---------------------------+-------------
 (1136300.5625,6102727.25) | Hauptstraße
 (1136600.1875,6074707.25) | Hauptstraße
 (1136799.1875,6101558.25) | Hauptstraße
 (1137051.3125,6074499.25) | Hauptstraße
(4 rows)

Wenn ich meine DB nicht mit “osm2pgsql --merc” kopieren würde, wären die Koordinaten schon im passenden Format.

Grüße, Max

Sieht ja ganz nett aus. Hab mir mal deine SQL-Abfrage angeschaut. In osm_line stehen ja alle straßennamen drin. Also wenn ich die Abfrage anstatt auf osm_roads auf osm_line mache bekomm ich doch die Koordinaten raus?

Bsp.:


select st_astext(st_transform(st_centroid(way),4326)),name from planet_line where name='Motzstraße' limit 4;
"POINT(9.48164755488011 51.3142094486382)";"Motzstraße"

Oder seh ich das jetzt falsch? Die Koordinate ist genau die mitte der Straße.

Des weiteren habe ich gesehen das in der Tabelle osm_ways z.B. der postal_code und name drin steht. Könnte man damit dann nicht arbeiten?

Hauptsächlich würde es mir schon reichen nach den Straßennamen zu suchen, also würde ja gegen die oben genannte Möglichkeit nichts gegensprechen? Das Problem ist nur noch, das ganze jetzt in Verbindung mit einer Stadt oder PLZ zu bringen.

EDIT:

SELECT st_astext(st_transform(st_centroid(way),4326)) FROM planet_polygon WHERE tags->'name' = 'Kassel';

Diese Abfrage gibt mir die Orte aus,soweit ich es bis jetzt getestet habe.

Ok… Nach weiteren Tests wird nicht jeder Ort ausgegeben.

Ja, in “roads” stehen alle Straßen. In “line” stehen alle Striche, die gemalt werden können, z.B. auch Flüsse. Ich hab mir angewöhnt, “roads” links liegen zu lassen, dann kann ich auch mal Flüsse suchen oder Stromleitungen oder so…

Ja, die Mitte des Strassenzuges. In einer halbkreisförmigen Straße liegt diese Mitte nicht auf der Straße, sondern irgendwo im Inneren des Halbkreises. Da gibts Bilder dazu. Als Alternative (“irgendwo in der Mitte, aber nicht ausserhalb”) gibt es “ST_PointOnSurface”. Ich weiss aber nicht, ob das auch für Linien gilt, ich kenne es nur für Polygone.

Die Tabellen “ways” und “nodes” und “rels” sind sowas wie Zwischenlager für osm2pgsql, wo die Daten lagern, bevor sie in line, polygon, point… geschrieben werden. Damit würde ich nur im Ausnahmefall arbeiten…

Da steht auch nur manchmal der postal_code drin. Nämlich immer dann, wenn der Mapper zusätzlich zu name=xxx, maxspeed=nn und highway=irgendwas auch noch einen postal_code für sinnvoll hielt. Darauf würde ich mein System nicht aufbauen.

Richtig. Der Strassenname allein ist leicht zu bekommen.

Das name-Tag allein ist ziemlich unzuverlässig. So findest Du auch alle Kneipen, die “Kassel” heissen und ein Building-Polygon haben. Und dafür vielleicht Deine gesuchte Stadt nicht, weil die offizielle Bezeichnung für Kassel eingetragen ist: “Freie Haupt- und Residenzstadt Kassel am Stadtbach” (übertrieben und frei erfunden, aber ähnliche Beispiele kann ich liefern). Also hier eher nach admin_level filtern. Und vielleicht “ST_PointOnSurface” statt Centroid, wegen halbmondförmiger Landkreise.

Grüße, Max

Nachtrag: Weil ich grad “WHERE tags->‘name’ = ‘Kassel’” sehe… “Tags” ist die Spalte, wo alles mögliche als hstore landet. Darauf hast du in der Regel keinen Index. Dein planet_polygon hat sicher auch “name” als Spalte, vermutlich auch indiziert. Nimm lieber die: WHERE name = ‘Kassel’"

Also wäre diese Abfrage richtig um an den Landkreis herrauszubekommen.

Dann müssten ja PLZ, Bezirke, Orte und Straßen ja in line, polygon oder point vorhanden sein?

Wie komme ich denn sonst an die Postleitzahl?

Habe ich eventuell die falschen bzw. nicht aussreichende Datenextrakte in die Datenbank importiert, die die benötigten informationen nicht enthält? Habe meine Daten von Geo-Fabrik

Jep, und den Admin-Level müsstest anpassen, je nachdem, ob Du Kreise, Kreisfreie Städte, Gemeinden… suchst. Ich hab hier kein Kassel, aber z.B. Starnberg gibt es mehrfach, als Kreis, als Stadt und als See(?):

osm=> select ST_AsText(ST_Transform(ST_PointOnSurface(way),4326)),name, admin_level,boundary  from osm_polygon WHERE admin_level = '6' AND name Like '%Starnberg%';
                st_astext                |   name    | admin_level |    boundary    
-----------------------------------------+-----------+-------------+----------------
 POINT(11.2904976148817 47.978756976312) | Starnberg | 6           | administrative
(1 row)

osm=> select ST_AsText(ST_Transform(ST_PointOnSurface(way),4326)),name, admin_level,boundary  from osm_polygon WHERE admin_level = '8' AND name Like '%Starnberg%';
                st_astext                 |      name       | admin_level |    boundary    
------------------------------------------+-----------------+-------------+----------------
 POINT(11.3355299176134 48.0063018366477) | Starnberg       | 8           | administrative
 POINT(11.3085309744874 47.9094240771543) | Starnberger See | 8           | administrative
(2 rows)

Jo. Bezirke, und Orte wahlweise als Polygon mit boundary=administrative und admin_level wie oben oder als Node mit place=city/town:

select  ST_AsText(ST_Transform(way,4326)),name,place from osm_point where place is not null and name='Starnberg';

                st_astext                 |   name    | place 
------------------------------------------+-----------+-------
 POINT(11.3499952984201 48.0000033948902) | Starnberg | town
(1 row)


Strassen in line (oder vielleicht manchmal in Polygon, falls es Plätze sind):

osm=> select  ST_AsText(ST_Transform(ST_PointOnSurface(way),4326)),name,highway from osm_line where name like '%Weg' limit 2;
                st_astext                 |      name       |   highway   
------------------------------------------+-----------------+-------------
 POINT(11.4622591327655 47.2904587764759) | Thaurer Weg     | track
 POINT(10.4540800690612 47.9813705644259) | Lichtenauer Weg | residential
(2 rows)

Postleitzahlen hängen oft an Hausnummern (in node oder in polygon am Gebäudeumriss) oder sie gibts in Polygonen mit den Postleitzahlengrenzen:

osm=> select  ST_AsText(ST_Transform(way,4326)),tags->'addr:street' as strasse from osm_point where tags->'addr:postcode'='80801' limit 2;
                st_astext                 |      strasse       
------------------------------------------+--------------------
 POINT(11.5850942983874 48.1594083948839) | Hohenzollernstraße
 POINT(11.5849299983874 48.1594452948839) | Hohenzollernstraße
(2 rows)

osm=> select (point(centroid(way))) as mittelpunkt,tags->'postal_code' as plz from osm_polygon where boundary='postal_code' limit 3;
        mittelpunkt        |  plz  
---------------------------+-------
 (1185629.4375,6154102.25) | 86850
 (1183396.9375,6144518.75) | 86866
 (1185854.3125,6182498.25) | 86465

Als Kombination daraus z.B. Straßen(stücke) mit “x” in Starnberg:

osm=>  select  name from osm_line where highway='residential' and name like '%x%' and exists (select way from osm_polygon where admin_level = '8' and name like '%Starnberg%' and st_contains(osm_polygon.way,osm_line.way));
         name          
-----------------------
 Felixweg
 Waxensteinstraße
 Nixenweg
 Max-Josef-Park
 Max-Zimmermann-Straße
 Max-Emanuel-Straße
 Max-Emanuel-Straße
 Maximilianstraße
 Waxensteinstraße
(9 rows)

Das dauert übrigens ewig, “st_contains” ist recht aufwändig zu rechnen. Ein Optimierungsansatz wäre, erstmal nur Straßen mit ‘x’ im 10x10km-Rechteck um die Ortsmitte von Starnberg auszuwählen (das geht schnell, weil dafür hat “way” seinen spatial index bekommen). Und man sieht schön, dass es mehrere “Max-Emanuel-Straße” gibt. Das sind alles Stücke einer grossen geteilten Straße.

Die Daten sind vermutlich schon die richtigen, aber es gibt verschiedene Arten, seine DB zu organisieren. Alles was ich hier getippt hab bezog sich auf osm2pgsql mit hstore. SunCobalt hat wohl ungefähr die gleiche wie ich, nur dass er seine Daten in lat/lon speichert, ich in mercator (was aber hier keinen Unterschied macht, man muss nur irgendwo umrechnen).

Was willst eigentlich machen? Ortspläne haben üblicherweise einmalig vorher ausgewertete Straßenlisten mit hinterlegtem Punkt zum hinzoomen. Eine Quiz für die Ortskundeprüfung müsste nicht nach PLZ prüfen und hätte keine “Ortsmittelpunkte”, für die Adresssuche müsstest nicht die Koordinate ausgeben…

Grüße, Max

hat sich erledigt

Gut, osm2pgsql habe ich auch genutzt.

Ich habe eine selbst geschriebene Windows-Applikation die eine OSM Karte anzeigt. In der ich eine Adresssuche implementieren möchte. Als Schnittstelle habe ich an die Koordinaten gedacht. D.h. Ich benötige die Lon/Lat Koordinaten um zu einen Punkt auf der Karte anzuzeigen. Es mangelt jetzt nur an der Komplexität der suche.

Außerdem möchte ich mehr über die Struktur der Datenbank wissen bzw. wie diese genau Arbeitet, welche Daten sie von wo benutzt um dies und das anzuzeigen.

Da hast du mir auch schon sehr bei geholfen :slight_smile: Vielen Dank für deine Hilfsbereitschaft.

EDIT: So ich glaube ich hab den Bogen nun raus :slight_smile:

Mit dieser Abfrage:


SELECT ST_AsText(ST_Transform(centroid(way),4326)) as Koordinaten, tags->'addr:Name' as Name, tags->'addr:city' as Stadt, 
tags->'addr:street' as Straße, tags->'addr:postcode' as Postleitzahl, tags->'addr:housenumber' as Hausnummer 
from planet_point 
WHERE tags->'addr:street' like '%Irgendeine Straße%' 
AND tags->'addr:housenumber' LIKE 'Irgendeine Hausnummer';

klappt es ja wunderbar. Bei der suche muss ich dann falls kein Ergebnis zurückt kommt, jedes mal die Suche einschränken und mehrere Abfragen machen und ggf. auch in anderen Tabellen suchen.

Gruß
mvollmer

Moin zusammen,

hab da noch eine Frage zu folgendem:

Kann man aus diesen mehreren Stücken eine Mitte finden?

Ich habe folgende feststellungen machen können:

Sind von der Straße…
… 1 Ergebnis vorhanden → Dieser ist auch die Mitte
… 2 Ergebnisse vorhanden → 2. Punkt ist die Mitte
… 4 Ergebnisse vorhanden → In meinem Beispiel ein Platz, bei dem die äußeren Punkte vorhanden sind. Keine Mitte
… 7 Ergebnisse vorhanden → Mitte ist (Anzahl der Ergebnisse / 2 + 1)

weitere Versuche habe ich bis jetzt nicht gemacht. Treffen diese Fälle auf alle Straßen zu?

Gruß
mvollmer

Nein, sorry.

Die Straßenstücke purzeln praktisch zufällig aus der Datenbank. Ich wüsste auch gerade nicht, wonach man die sortieren sollte.

Auch die Ausrichtung der Stücke muss nicht zusammenpassen, es kann sein, dass zwei Enden zusammenstoßen, statt dass das Ende eines Stückes auf den Anfang der Weiterführung trifft. Manchmal sind Straßen unterbrochen, z.B. von einem Platz. Und Straßen sind nicht immer linienförmig, manche verzweigen sich und haben dann 2 Stücke mit 3 Enden wie ein “T”.

Ich würde mich von der Vorstellung trennen, dass eine Straße überhaupt einen Mittelpunkt hat. Falls man eine Straße grafisch darstellen will, sollte man einen Strich malen. Falls man zu einem Punkt den Straßennamen sucht, ist das der Name des Straßenstücks mit der geringsten “st_distance(punkt,weg)”. Der nächstgelegenen Punkt auf der Straße zu einem Punkt daneben wäre vermutlich mit ST_Line_Locate_Point rauszubekommen (hab ich aber noch nie probiert).

Grüße, Max

Okay, dann weiß ich bescheid. Letzendlich muss ich eigentlich auch nicht die Mitte sondern nur irgend einen Punkt haben, daher ist es ok. Aber war nur ein Versuch/Gedanke :slight_smile:

Vielen Dank für die Aufklärung.