Daten gefiltert über Overpass API herunterladen

Ui, das Programm wird berühmt! :wink:

Ich steh trotzdem zu diesem Weg. Bei Milliarden von Einzelvergleichen macht es halt schon etwas aus, ob man nur den relevanten Teil einer Zeichenkette vergleicht oder immer die komplette Zeichenkette. osmconvert ist ein Kompromiss, der auf Geschwindigkeit ausgelegt ist. Wer XML-Dateien auf XML-Syntax-Treue parsen will oder damit rechnet, dass das vorausgehende Schreibprogramm einen XML-Syntax verwendet, der für OSM nicht definiert bzw. dokumentiert ist, muss eben ein anderes Programm verwenden - welches dann natürlicherweise langsamer läuft.

Manche Software bietet sogar beide Wege an: einen vollwertigen XML-Parser und eine Art “Abkürzung”, die den XML-Syntax nicht komplett prüft, aber eben schneller ist. Wenn ich mich recht erinnere, macht das osm2pgsql so. Den Luxus dieser Auswahl hab ich mir gespart, weil die “Abkürzung” sehr zuverlässig funktioniert und halt einfach flott arbeitet.

Ich kenne den Code deines Programms nicht.

Aber wenn ich es richtig verstehe, dann musst du vergleichen, ob ein gegebener String einem von n gegebenen Werten entspricht. Dazu eignet sich ein TreeSearch Algorithmus. Ich habe es mit solch einem Algorithmus geschafft, ca. 800 MB/sec auf 10000 Suchbegriffe GLEICHZEITUNG zu untersuchen (single thread).

Dazu muss die Liste der Suchbegriffe in eine Baumstruktur umgewandelt werden. Jeder Node besteht aus einem Array von z.B. 256 (für 1 Byte) Child Nodes. Am Anfang sind alle Childnodes null. Nun wird für jeden Buchstaben des Suchwortes nacheinander ausgehend vom root-Node ein neuer Knoten erzeugt (falls noch keiner existiert).

Beispiel: Begriff “node” einfügen:
node1: [a]=null, … [n]=node2, … [z]=null, hit=null
node2: [a]=null, … [o]=node3, … [z]=null, hit=null
node3: [a]=null, … [d]=node4, … [z]=null, hit=null
node4: [a]=null, … [e]=node5, … [z]=null, hit=null
node5: [a]=null, … [z]=null, hit=‘node’

Zusätzlich Begriff ‘note’:
node1: [a]=null, … [n]=node2, … [z]=null, hit=null
node2: [a]=null, … [o]=node3, … [z]=null, hit=null
node3: [a]=null, … [d]=node4, … [t]=node6, … [z]=null, hit=null
node4: [a]=null, … [e]=node5, … [z]=null, hit=null
node5: [a]=null, … [z]=null, hit=‘node’
node6: [a]=null, … [e]=node7, … [z]=null, hit=null
node7: [a]=null, … [z]=null, hit=‘note’

Zusätzlich Begriff ‘name’:
node1: [a]=null, … [n]=node2, … [z]=null, hit=null
node2: [a]=node8, … [o]=node3, … [z]=null, hit=null
node3: [a]=null, … [d]=node4, … [t]=node6, … [z]=null, hit=null
node4: [a]=null, … [e]=node5, … [z]=null, hit=null
node5: [a]=null, … [z]=null, hit=‘node’
node6: [a]=null, … [e]=node7, … [z]=null, hit=null
node7: [a]=null, … [z]=null, hit=‘note’
node8: [a]=null, … [m]=node9, … [z]=null, hit=null
node9: [a]=null, … [e]=node10, … [z]=null, hit=null
node10: [a]=null, … [z]=null, hit=‘name’

Beim Suchen:
node = root;
c = firstchar;
while (node!=null && node.hit==null) {
node = node[c];
c = c.next;
}
if (node!=null) {
Treffer mit node.hit !
}

Das schöne ist, das die Anzahl der Suchworte in Baum fast keine Rolle spielt. Man muss für jedes Zeichen des zu untersuchenden Strings immer nur EINEN Vergleich vornehmen!

Falls noch Fragen offen sind, helfe ich dir gerne!

Grüsse

mdk

Hallo mdk, danke für das Angebot und die Mühe, die du dir gemacht hast!

Der Fall ist aber aus meiner Sicht so nicht vergleichbar, weil es in .osm-Dateien auf der äußeren Ebene nur sehr wenige verschiedene XML-Tags gibt. Zum Beispiel: “<node”, “<way”, “<relation”, "<create, “<modify”, “delete”. Hier ist ein hart codierter Vergleich deutlich schneller als die Suche in einem Baum.

Bei anderen Aufgaben (Bounding-Polygon, pbf- und o5m-Stringtabellen, --all-to-nodes usw.) verwendet das Programm je nach Eignung der Methode verkettete Listen, Hash-Tabellen, Binärsuche usw. Wenn du dort trotzdem irgendwo Optimierungsmöglichkeiten entdeckst, immer her damit! :slight_smile:

Hallo,

nach langer Zeit noch etwas Senf von mir zu diesem Thema. Unten mein Perlskript, das ich mir auf die Schnelle zusammengepfuscht habe. Es erwartet als ersten übergebenen Parameter eine Koordinatenbox der Form, wie sie auch für XAPI verwendet wird also bspw. “1.234,56.789,9.876,57.321” und als zweiten Parameter den Pfad zu einer (lokalen) Datei mit Renderregeln für Osmarender. Das Skript lädt dann alle im Rulefile verwendeten Tagklassen für die angegebene Box runter und fasst diese Daten anschließend mit osmconvert zusammen. Im Skript selbst muss nur der korrekte Pfad zu osmconvert eingetragen werden.
Die so entstehende output.osm-Datei kann anschließend an Osmarender zum Rendern übergeben werden. Reduziert die herunterzuladende Datenmenge (und damit auch die Renderzeit) ganz erheblich, wenn man nur sehr wenige Elemente in relativ großen Bereichen rendern will.

Ohne jede Garatie für Funktionieren und eventuell auftretende Probleme oder Schäden. Aber vielleicht hilfts ja dem einen oder anderen:



use strict;

my $coords=$ARGV[0];
my $rulefile=$ARGV[1];
my $osmconvertpath='/pfad/zu/osmconvert/osmconvert32';
my $i=0;
my $wgetcmd;
my $osmconvertcmd;
my $delcmd;
my @elements;

#Koordinaten aus erstem Parameter filtern
$coords=~s/[^\d,.]//g;

#Benötigte Klassen aus der Rule-Datei auslesen
open INPUT, "<$rulefile" or die "Can't open Rulefile $rulefile: $1";
while (<INPUT>){
    if (m!^<rule e=".*?" k="(.*?)" v="(.*?)">!){
        push @elements, "$1=$2";
    }
}
close INPUT;

#Daten herunterladen
foreach (@elements){
    $wgetcmd="wget -O $i.osm \"http://www.overpass-api.de/api/xapi?*[bbox=$coords][$_][\@meta]\"";
    `$wgetcmd`;
    $osmconvertcmd.="$i.osm ";
    $i++;
}

#Einzelne Dateien zusammenführen
$osmconvertcmd="$osmconvertpath $osmconvertcmd--fake-version -o=".'output.osm';
`$osmconvertcmd`;

#Einzeldateien löschen
$i=0;
foreach (@elements){
    $delcmd="rm ".$i.'.osm';
    `$delcmd`;
    $i++;
}


print "Fertig\n";