Files

3.6 KiB
Raw Permalink Blame History

GTFS-Verbindungssuche: RAPTOR real erprobt (2026-08-19)

Kontext: Webseite urlaub.perfekt-ohne-en.de (Zugsuche, nur Nahverkehr/kein ICE). Nutzer stellte echte GTFS-Datei bereit (Regional/S-Bahn) — Verarbeitung brachte mehrere harte Lektionen.

Lektion 1: RAPTOR verbessert, aber ist KEINE fertige Lösung

Einfacher Dijkstra auf GTFS ist instabil bei grossen Knoten: benachbarte Ziele ergaben absurde Differenzen (Mainz→Berlin 11h vs. Nachbar Wiesbaden 3h — unmoeglich). RAPTOR (Round-Based) ist der richtige Algorithmus und verbessert die Konsistenz (Mainz & Wiesbaden → Berlin wurden konsistent ~8h22).

ABER: RAPTOR erzeugt weiterhin einzelne absurde Fernwerte (z.B. Mainz→Berlin ~22h, real Regional ~7-9h; Trefferquote ~66-95%). Ein Algorithmus mit solcher Einzelfehlerquote darf NICHT als finale Fahrzeit-Quelle ausgegeben werden.

Praxisfix (Nutzer-Entscheidung „3 dann 1"):

  • Option 3 (sofort): nur team-verifizierte Kernzeiten konkret anzeigen (Plausibilitaets-Anker: Trier→Saarbruecken ~1h, Koeln→Aachen ~50min, vom Team bestaetigt). Alle anderen Verbindungen → fahrzeit_h='pruefen' in SQLite; Template rendert stattdessen orangen Hinweis „vor Fahrt prüfen". NIE absurde/inkonsistente Zahl als real stehen lassen.
  • Option 1 (danach): robuste Suche erst auf die Seite schreiben, wenn JEDER Wert separat gegen einen Plausibilitaets-Anker verifiziert ist.

Lektion 2: Konsistenz-Check = Nachbar-Ziele gegeneinander pruefen

Der schnellste Fehlerdetektor: benachbarte Ziele vergleichen. Mainz→Berlin darf nicht dramatisch von Wiesbaden→Berlin abweichen (gleiche geographische Lage). Erst wenn das Cluster konsistent ist, Werte freigeben.

Lektion 3: PDF-Haltestellenliste via VORAB-PFAD-CACHE

Nutzerwunsch: PDF soll die komplette Verbindung (von → zwischenhalte → nach) zeigen, nicht nur Start/Ziel. On-the-fly-Routing bei jedem PDF-Aufruf ist zu langsam (RAPTOR ~40-200s → nginx 504 Gateway Timeout).

Lösung: Vorab einmalig Pfad-Cache bauen (pfade_cache.json), NUR die Kern-Ebenen 1+2 (~1.900 eindeutige von|nach-Paare; Ebene 3 = Kleinstaedte braucht keine eigenen PDFs). PDF-Route liest json.load(cache)[f"{start}|{ziel}"]["seg"] → Ladezeit von 504 auf ~0,4s. Wiederverwendbares Muster: Wenn On-the-fly-Berechnung zu langsam ist, vorab einen Cache bauen und die Route daraus lesen.

  • Template ergaenzt Start-Stadt als ersten + Ziel-Stadt als letzten Eintrag, damit die Liste immer den Rahmen von → ... → nach bildet.

Lektion 4: GTFS-Datenmodell-Fallen

  • stops.txt Spaltenreihenfolge ist NICHT stop_id,stop_name,... — sie ist stop_name,parent_station,stop_id,stop_lat,stop_lon,.... Beim Import die echte stop_id aus den richtigen Spalten ziehen (parent_station ist oft die nutzbare ID).
  • Ein Bahnhof hat mehrere stop_ids (Saarbruecken Hbf hat 6, nur je 1 aktiv in st; Koeln Hbf hat 2). Geo-Merging (<350m) gruppiert sie; sonst matcht die Suche auf eine tote ID und liefert „keine Verbindung".
  • Zeit-Spalten: HH:MM ODER HH:MM:SS — to_sec() muss beides handhaben.
  • COROS/Efa-Text-APIs liefern oft \\n als literalen Backslash-n statt echten Zeilenumbruchen → vor dem Parsen text.replace('\\n','\n').

Performance-Falle bei Gesamt-Neuberechnung

Pro-Profile-Query (33 Abfahrtszeiten) × pro Verbindung ist zu teuer fuer ~12.000 Verbindungen (huubai 18h). Effizienter: EIN Dijkstra/RAPTOR je eindeutiger Start-Bahnhof (Ausbreitung zu allen Zielen in einem Lauf) → ~250 Starts statt 12.000 × viele → von Stunden auf ~10min. Cache die Ausbreitung je Start und lese die Ziel-Ankunft daraus ab.