Statistiken der OSM Datenbank

Dafür würde ich nicht auf die API zurückgreifen um dort gefilterte Wege auszulesen, sondern wöchentlich sämtliche OSM-Daten für das ganze Gebiet holen, archivieren und dann erst filtern und auswerten. Bei dem Gebiet einer Stadt sollte das noch gut gehen. Ich würde dafür eine Datenbank basteln, aber sicher gibt es auch andere Wege.

Du wirst nämlich in einem halben Jahr feststellen, dass Du etwas wichtiges vergessen hast (*) und hast dann keine Möglichkeit mehr, das rückblickend zu korrigieren, wenn du nur vorgefilterte historischen Daten hast.

Grüße, Max

() Nur mal so als Beispiel: Du wirst du feststellen, dass sich die Länge der Fusswege plötzlich verdoppelt, wenn jemand (highway=, sidewalk=both) zu getrennt gemappten Bürgersteigen ändert. Oder du hast schlicht highway=steps vergessen oder eine ungewöhnliche Kombination aus highway=* und foot=*

Wenn das Gebiet nicht allzu groß ist, lassen sich auch “historische” Daten (im Sinne von: wie sah die Datenbank am Tag x aus?) abfragen: (link).

Das habe ich auch schon gemacht (mit Python und overpy), es geht auch gut.


import overpy

api = overpy.Overpass()

DEBUG = False

def debug(str):
    if DEBUG:
        print(str)

def objects_in_time_and_space(relationid,y,m,d, kv={'key':'natural','value':'tree'}):
    """Liefert ein tupel mit (anzahl_nodes, anzahl_ways) zurück.
    Der dict kv gibt an, nach welchem Key und welchem Value gesucht wird. Default natural=tree
    """
    areaid = relationid + 3600000000
    result = api.query("""
    [timeout:250]
    [date:"%d-%02d-%02dT00:00:00"]
    ;
    area(%d)->.searchArea;
    (
      node
        ["%s"="%s"]
        (area.searchArea);
      way
        ["%s"="%s"]
        (area.searchArea);
    );
    out %s;
        """ % (y,m,d,areaid,kv['key'],kv['value'],kv['key'],kv['value'],'body' if DEBUG else 'skel'))
    debug("*** nodes (%d) ***" % len(result.nodes))
    for node in result.nodes:
        debug("%s (%d)" % (node.tags.get("name", "(unbenannt)"), node.id ))
        debug("  natural: %s" % node.tags.get("natural", "n/a"))
        debug("  Lat: %f, Lon: %f" % (node.lat, node.lon))


    debug("*** Ways (%d) ***" % len(result.ways))
    for way in result.ways:
        debug("Name: %s" % way.tags.get("name", ""))
        for node in way.nodes:
            debug("    Lat: %f, Lon: %f" % (node.lat, node.lon))
    return (len(result.nodes), len(result.ways))

if __name__ == "__main__":
    
    #relid = 62677 #LK Osterode
    #relid = 51477 #BRD
    relid = 1421436 #AL8 Clausthal-Zellerfeld

    demo = 2

    
    if demo == 1:
        print("  Berggipfel (natural=peak) jeweils am Monatsersten 2014-2015")
        print("time;nodes;ways")
        for year in range(2014,2016,1):
           for month in range(1,13):
                n = objects_in_time_and_space(relid,year,month,1,{'key':'natural','value':'peak'})
                print("%d-%02d-%02d;%d;%d" % (year,month,1,n[0],n[1]))
    elif demo == 2:
        print("  Default (natural=tree) am 1.3.2015")
        y = 2015
        m = 03
        n= objects_in_time_and_space(relid,y,m,1)
        print("time;nodes;ways")
        print("%d-%02d-%02d;%d;%d" % (y,m,1,n[0],n[1]))
    elif demo == 3:
        print("  Gipfel (natural=peak) am 23.3.2015 mit DEBUG")
        DEBUG = True
        y = 2015
        m = 03
        d = 23
        n= objects_in_time_and_space(relid,y,m,d,{'key':'natural','value':'peak'})
        print("time;nodes;ways")
        print("%d-%02d-%02d;%d;%d" % (y,m,d,n[0],n[1]))


Vorteil: keine lokale Datenhaltung nötig. Nachteil: Belastung der Overpass-Instanz.

Die Weglänge muss man sich hinterher aber sowieso noch selbst berechnen.

edit: bugs im Programm:

  • Muss noch sleep machen zwischen den “repeated requests”, um nicht in Sperren zu laufen
  • Debuggen von ways geht nicht, weil ich nur den Way und nicht seine nodes hole
    …aber das fixen sei dem geneigten Studenten überlassen g

Hallo,
in die selbe Richtung habe ich auch schon gedacht. Allerdings wäre es schön, wenn ich auch ältere Daten nutzen könnte. Kann man den Stand der Datenbank z.B. am 1.1.2014 abfragen?

Das ist super! Danke für den Tipp und bringt mich schon mal weiter.

Das schaue ich mir am WE mal näher an. Danke für die Hilfe! Ich nutze ein MacBook und bin noch etwas unbedarft beim programmieren (ich fange gerade erst an). Kann ich den Code einfach in einem Terminal ausführen (Python ist auf dem Mac installiert.)?

Noch eine Nachfrage zu dieser Anmerkung: “Nachteil: Belastung der Overpass-Instanz.” Irgendwie fehlt mir da noch etwas Information. Wann wird die Overpass-Instanz unverhältnismäßig belastet? Sprich auf was muss ich achten? Ich will nicht aus Unwissenheit irgendwelchen Unmut auf mich ziehen.

Nein, der muss in eine Datei geschrieben werden (zum Beispiel mit einem Texteditor), normalerweise nimmt man dazu die Endung “.py”.

Dann kannst du im Terminal “python ” aufrufen, dann wird die Datei ausgeführt.

Du musst noch die beiden Zeilen


        for node in way.nodes:
            debug("    Lat: %f, Lon: %f" % (node.lat, node.lon))

löschen oder auskommentieren (vorne ein Schweinegatter/Hashzeichen: “#” davorschreiben), die sind noch fehlerhaft.

Vorher musst du das Python-Modul “overpy” installieren. Ich kenn mich mit Macs nicht aus, aber das sollte mit dem Kommando “pip install overpy” gehen.

Sehr löbliche Einstellung!

Mir klemmt die API den Zugriff ab, wenn ich mein Skript da 5 Mal hinternander mit demo=1 laufen lasse. Man kann das entschärfen, wenn man nach jeder Abfrage 5 Sekunden wartet. Das geht mit


import time

ganz oben, und dann an der Stelle wo man 5 Sekunden warten will, mit


time.sleep(5)

Eine sinnvolle Stelle ist entweder die Definition der Funktion objects_in_time_and_space (am Anfang oder am Ende), oder jeweils beim Aufruf der Funktion (vorher oder nachher).

Beachte auch bei Python, dass die Einrückung mit (im Beispiel) Leerzeichen wichtig ist.

Vielen Dank für die Erklärungen zu Python. Da habe ich mein Projekt für das WE.

Bei der OverpassAPI hab ich Dich jetzt so verstanden, dass die Mitarbeit einfach verweigert wird, wenn die Anfrage zu aufwendig/zu oft hintereinander passiert. D.h. ich kann mich auf den Automatismus verlassen und kann die API gar nicht lahm legen (z.B. mit Abfragen die eine unendliche Schleife beinhalten oder unendlich vielen Abfragen)?

So habe ich das auch verstanden. Die API klemmt dich irgendwann ab, nachhaltig kaputtmachen kannst du da soweit ich das weiss nix. Aber das ist nur mein Halbwissen; habe kurz im Wiki gesucht aber eine Usage Policy für die Overpass-API nicht gefunden.

Auf http://wiki.openstreetmap.org/wiki/Overpass_API#Introduction steht

http://download.geofabrik.de/europe/germany/

dann Weiterverarbeitung mit einer modifzierten Version von https://github.com/osmcode/osmium-contrib/tree/master/road_length (braucht für Deutschland ~ 3 Minuten – der größte Teil der Zeit geht für das Einlesen der OSM-Daten und Zusammenbauen der Ways aus den Nodes drauf) Dafür brauchst du halt C+±Kenntnisse.

Ansonsten könntest du dir auch die Daten in eine PostGIS-DB importieren und dort mittels


count(highway) from planet_osm_lines where highway='residential';

die Wohnstraßen (Stückzahl, nicht Länge) zählen. Die Funktion zum Messen der Länge verrät dir das PostGIS-Manual. Der Import in PostGIS dürfte aber länger dauern als ein paar Durchläufe von road_length.

Viele Grüße

Michael

Das ist eigentlich nur die halbe Miete. Um beliebige Zeitpunkte mit der Methode zu rekonstruieren braucht man einen Full History Dump und das Osmium Tool, um genau für diesen Zeitpunkt ein Snapshot zu erzeugen. Danach geht’s weiter mit Road Length. Übrigens braucht man zum Compilieren der Tools ganz sicher keine besonderen C++ Kenntnisse.

Das ist schon die Usage Policy (steht auch so in der Spaltenüberschrift). Wenn Du extrem viel Last erzeugst, könnte es aber sein, dass Roland irgendwann deine IP blockiert. Für den normalen “turbo”-Benutzer wird das jedoch praktisch nicht passieren. :sunglasses:

Bonk. Wald, Bäume und so. Danke!

Hallo mmd,

Wenn du meinem Link auf den Downloadserver gefolgt wärst, hättest du gesehen, dass es dort ein PBF-File vom 1.1.2014 gibt. Das erspart einem die Verarbeitung des Full-History-Planets.

Viele Grüße

Michael

Das hab ich natürlich vorher geprüft, deshalb habe ich auch von einem beliebigen Zeitpunkt gesprochen. Für den Spezielfall 1.1.2014 funktioniert es (Nico hatte das ja nur als Beispiel genannt). Für den 2.1.2014 findet sich auf dem Download-Server von der Geofabrik jedoch schon kein passendes File mehr. Aber klar, wenn zufällig für den Tag ein Extrakt vorliegt, spart man sich den Full-History-Teil.

Ich habe leider mit der Overpass-API bislang keine gute Erfahrung gemacht. Jedenfalls, wenn man eine Abfrage online laufen lässt. Sowas hier z.B. ist tödlich:

Selbst bei kleinen Städten bekomme ich immer ein Timeout :slight_smile:

Kann ich nicht nachvollziehen. Für http://overpass-turbo.eu/s/cVI dauert das Rendern der 4MB-Antwort länger als die Ausführung der Abfrage. Ist allerding auch eine BBOX-Abfrage, keine auf ein Suchgebiet beschränkte.

Falls die Abfrage innerhalb einer Polygon-Grenze aber die Antwortzeit zu stark erhöht, kann man natürlich auch die Daten in einem Rechteck abfragen und die runtergezogenen Daten hinterher bei sich auf dem Rechner mit der gewünschten Grenze clippen. Das geht mit ogr2ogr (siehe http://www.gdal.org/ogr2ogr.html , Argument “-clipsrc”).

Ja, jetzt klappt es. Habe wohl einen schlechten Tag erwischt (habe es aber jetzt schon in PSQL realisiert g).

Da kann ich nur empfehlen, die Query als overpass turbo Link zu posten oder in hartnäckigen Fällen auch mal ein GitHub-Ticket aufzumachen. Wir können uns das dann mal in Ruhe auf der dev-Instanz anschauen und ggfs. weiter analysieren.

Danke, werde ich das nächste Mal tun.