Wie ich versucht habe, eine Kartensuche nach Treibern zu reparieren

Dies ist eine Geschichte darüber, wie ich versucht habe, ein seltsames Problem zu lösen, das mich selbst daran gehindert hat. Mit Blick auf die Zukunft werde ich sagen, dass ich mit der resultierenden Lösung zufrieden bin und die Anwendung zu ihrem logischen Ende gebracht habe. Um es jedoch vollständig ausführen zu können, benötigen Sie mehr Ressourcen. Daher habe ich beschlossen, eine Pause einzulegen und die Leute zu fragen, ob es jemand anderes benötigt. Zu diesem Zweck (und auch nur zum Reden) schreibe ich hier.

Zwei Worte über mich: Ich lebe in Dublin, Irland, arbeite als Programmierer. Es sitzt nicht genau vor Ort, deshalb habe ich in meiner Freizeit zu Hause verschiedene Projekte gesehen, hauptsächlich auf dem Tisch. Ich schreibe zum ersten Mal über Habré, obwohl ich seit vielen Jahren lese.

Das Problem


Vor langer Zeit, als ich viel an unbekannte Arbeitsorte reisen musste, bemerkte ich, dass die Standardsuche auf Karten heute für Fahrer absolut nicht mehr anwendbar ist. Schauen Sie: Sie fahren in einem unbekannten Gebiet und haben einen Benzinpfeil bei Null. Deine Handlungen? Wenn ich in diesem Moment nicht alleine im Auto bin, sage ich dem Passagier: "Suchen Sie während der Fahrt nach einer Tankstelle in der Nähe." Denn wenn Sie es selbst tun, müssen Sie die folgenden Aktionen ausführen:

  1. Um aufzuhören
  2. Geben Sie in der Kartenanwendung bei der Suche "Benzin" ein (oder klicken Sie auf eine der Schnellschaltflächen, die einige Karten jetzt bieten).
  3. Die Anwendung führt eine Suche durch und zeigt Ihnen eine riesige Karte mit einem Dutzend Tankstellen
  4. Sie versuchen herauszufinden, welches Ihnen am nächsten liegt, und klicken darauf, um eine Route zu erstellen

Meiner Meinung nach ein Albtraum. Zunächst müssen Sie anhalten oder zumindest auf eine Ampel warten. Weil die Karten komplex und die Symbole klein sind. Zweitens sagt Ihnen die Nifig-Karte nicht, was die nächste Tankstelle ist. In dieser Hinsicht ist Google am schlimmsten: Selbst in den Ergebnissen in Form einer Liste schiebt es hartnäckig nicht den nächstgelegenen Ort nach oben, und der am besten bewertete / mit Fotos / bezahlte / ich habe keine Ahnung.



Nun, der dritte Faktor: Wir ziehen um. Das Ergebnis, dass die Karten ausgestellt wurden, war für einen bestimmten Punkt relevant, aber wir sind bereits weit davon entfernt. Haben Sie bemerkt, dass selbst die von Google festgelegte Route nicht automatisch aktualisiert wird, wenn wir verschoben haben? Nur wenn die Navigation bereits gestartet wurde, wird sie neu erstellt.

Im Allgemeinen ist das Problem klar. Logik, die für Fußgänger und ihre Bedürfnisse, für Fahrer funktioniert, ist über nichts. Die Bewertung des Ortes und die Art der Küche dort sind mir egal - ich brauche, ohne von der Straße abgelenkt zu werden, in Echtzeit einen Weg zur nächsten Tankstelle, Gebühr, Parkplatz, Geldautomat usw.

Idee


Versuchen wir nun, das ideale Suchszenario zu ermitteln. Das Kriterium lautet wie folgt:

  • Die Interaktion ist kurz und klar, um den Fahrer nicht abzulenken
  • transparente entfernungsbasierte Ausgabe
  • Echtzeit-Update

Das erste, was darum bittet, ist, die einmalige Standardsuche durch einen Scan zu ersetzen. Das heißt, die Aktionskette ist ungefähr so:

  1. Startete einen Scan
  2. Reiten, aktualisierte Ergebnisse in Echtzeit anzeigen
  3. Wenn mir etwas gefallen hat, habe ich geklickt und die Route gepflastert

Sie bestimmen die Suchkriterien im Voraus - tatsächlich ist dies die Art des Ortes und der Radius des Scans. Während sich das Auto bewegt, funktioniert die Anwendung wie ein Radar. Ziemlich schnell wurde klar, dass der Radius erstens nicht rund ist, sondern in Form einer Isolinie. Zweitens sollte es nicht nach Entfernung, sondern nach Zeit gebaut werden, da Minuten viel leichter wahrzunehmen sind als Kilometer.

Dann dachte ich über eine Möglichkeit nach, die Ergebnisse auszugeben. Genauer gesagt, brauche ich überhaupt eine Karte? Der Fahrer betrachtet die Anwendung mit einem Auge und interagiert mit einem Finger - er benötigt keine Karte, sondern einen großen Text und große Schaltflächen. Daher entschied ich sofort, dass der Hauptbildschirm eine Liste sein würde, und ich könnte zuerst eine Karte hinzufügen und dann sehen, ob ich sie verlassen sollte.

Planen


Da ich meine eigene Besonderheit bei Stretching-Projekten kannte, entschied ich mich, mir 2 Monate für alles zu geben - am Ende traf ich mich in 3. Im Prinzip ist die Anwendung recht einfach:

  1. Client von zwei Bildschirmen (Suche, Liste und Karte)
  2. Sendet regelmäßig seine Koordinaten, den Suchradius und die Art der Orte an den Server
  3. Der Server erstellt rechtzeitig eine Isolinie (übrigens hat er seinen Namen in Englisch - Isochron), führt eine Suche an Orten durch und gibt eine Liste zurück

Klingt nach einer leichteren Lunge. Ich hatte bereits einige Erfahrungen in der Kartografie (vor ein paar Jahren habe ich ein Immobilienportal erstellt, in dem die Suche auf der Karte war), sodass der Stapel im Backend sofort klar war:

  • Importieren Sie Daten aus OpenStreetMaps in Elasticsearch
  • OpenTripPlanner zum Erstellen von Konturen

Auf dem Client, dachte ich, entschied man sich für das neue Framework von Google - Flutter. Es ist plattformübergreifend, sehr flexibel und ermöglicht es Ihnen, vollwertige Anwendungen mit einem Minimum an Code zu erstellen. Natürlich ist es roh und es ist nicht klar, was in der Produktion ist, aber es sieht perfekt für das Prototyping aus. Es muss klargestellt werden, dass ich zu diesem Zeitpunkt Erfahrung in der nativen Entwicklung für Android hatte (ich war ein Teamleiter) und mich sozusagen entschied, mich dem Feind zu stellen. Der Feind war nicht so beängstigend.

Implementierung


Die erste Prototypanwendung war sehr schnell fertig - Flutter hat eine niedrige Einstiegsschwelle und eine verständliche reduxähnliche Philosophie. Seltsamerweise war auch die deklarative Beschreibung der Schnittstellen sowie der Hot-Neustart (React Native, Ihre Bitmap) angenehm. Im Allgemeinen war der Eindruck, dass Google die meisten angeborenen Krankheiten früherer Versuche ausmachte. Ich verstehe jedoch Leute, die vielleicht nicht darauf eingehen möchten - jemand mag Dart, eine begrenzte Anzahl von Widgets nicht und das hier angebotene „visuelle Debug“ ist etwas sehr Rohes.

Im Backend habe ich Folgendes gemacht:

  1. Nominatim geliefert, OpenStreetMaps-Datenextrakt ( hier aufgenommen ) mit seinem Standarddienstprogramm osm2pgsql in seine Datenbank hochgeladen. Warum habe ich mich dem kleinen, aber sehr angenehmen Open-Sour-Geocoder Photon zugewandt? Ich habe es bereits in einigen Projekten verwendet - es generiert einen Elasticsearch-Index, importiert dort Daten aus der Nominatim-Datenbank und sucht nach diesem Index. Ich mag es mit Geschwindigkeit und reinem Mapping (zum Beispiel habe ich Pelias ausprobiert und es hat mir weniger gefallen). Das Hauptproblem ist die alte Version des Gummibandes, aber in meinem Fall brauchte ich nicht die Funktionalität des Geocoders selbst, sondern nur die Daten. Nach dem Import habe ich den Index auf die Installation des Gummibandes der neuesten Version mit reiner Seele übertragen. Warum habe ich mich übrigens für Elasticsearch entschieden? Es ist sehr schnell und hat die Funktion, Koordinaten durch Polygon zu finden.
  2. Die Deponie - auch bekannt als Isochron - hat zunächst OpenTripPlanner für mich generiert. Dies ist ein ziemlich guter Open Source Routenplaner. Es funktioniert wie folgt: Es verwendet denselben OpenStreetMaps-Extrakt und kompiliert ihn zu einem großen Straßendiagramm, das als separates Objekt auf der Festplatte gespeichert wird. Wenn der Server gestartet wird, wird dieses Diagramm in den Arbeitsspeicher geladen und alle Routen werden durchsucht. Vorteile: schnelles Aufnehmen, reichhaltige Funktionalität (z. B. Konturen aus der Box) und gute Geschwindigkeit. Nachteile: Diese Geschwindigkeit hängt von der Größe des Arbeitsspeichers ab, und die Dokumentation ist äußerst widerlich. Nur monströse Dokumentation. Vietnamesische Rückblenden.
  3. Ich habe eine kleine API auf die Python geworfen, die die Art des Ortes und den Suchradius in Sekunden annimmt, ein Polygon von OpenTripPlanner anfordert und dann in Elasticsearch danach sucht. Es fordert eine Route zu jedem gefundenen Ort an (erneut von OpenTripPlanner), nimmt seine Länge und Zeit in Anspruch. Danach werden alle gesammelten Daten schön verpackt und zurückgegeben.

Ich habe die Ergebnisse aktualisiert, indem ich die Koordinaten des Geräts um 5 Meter verschoben habe. Die Karte ist statisch - ich habe gerade eine API für statische Google Maps verwendet (wie Sie sehen können, ist dies der einzige Ort, an dem das Unternehmen dennoch in unsere gemütliche Open-Sourse-Welt gekrochen ist). Die erste Implementierung sah folgendermaßen aus:







Nachdem ich mit der Anwendung gespielt hatte, beschloss ich, die Karte auszublenden. Sie hat gut verstanden, für welches Polygon die Suche gemacht wurde, und sie sah amüsant aus - es war interessant zu beobachten, wie dieser Oktopus in Echtzeit seine Form ändert. Diese Unterhaltung half der Anwendung jedoch nicht, ihre Funktionen zu erfüllen, und nahm ein Drittel des Bildschirms ein.

Mir kam auch der Gedanke, einen Pfeil hinzuzufügen, der die Richtung zu jedem Ergebnis angibt. Es hat so funktioniert:

  1. Erinnern Sie sich an Ihre vorherigen Koordinaten
  2. Beim Schalten legen wir die Route von der vorherigen Position zur aktuellen
  3. Wir nehmen das letzte Segment unserer Route und vergleichen jedes Ergebnis mit dem ersten Segment der Route. Da sie entlang desselben Straßennetzes verlegt sind, liegt der Winkel zwischen ihnen mit einer Wahrscheinlichkeit von 99% nahe bei 0 oder 180.

Dieser sehr einfache Trick erleichtert das Verständnis, ob wir bereits auf den Ort zusteuern oder ob wir uns umdrehen müssen.



Zu diesem Zeitpunkt war ich sehr zufrieden mit der resultierenden Anwendung und entschied mich, sie in mehreren Ländern bereitzustellen. Dennoch ist Irland ein sehr kleiner Staat, und der elastische Index und das Straßendiagramm waren klein. Zum Testen habe ich mich entschlossen, das benachbarte Großbritannien anzuschließen. Es ist ungefähr viermal größer und hat ein viel dichteres Straßennetz (insbesondere die Hauptstadt und Großstädte). Und dann trat ein Problem auf.

Elasticsearch hat den erhöhten Index erwartungsgemäß recht gut verdaut, aber mit OpenTripPlanner ist ein vollständiger Fehler aufgetreten. Es ist in Java geschrieben und generiert, wie oben erwähnt, ein Diagramm der Straßen, so dass nach dem Laden in den Arbeitsspeicher. Das Diagramm für Irland war 1 Gigabyte, für Großbritannien bereits 5. Es war natürlich möglich, es in Länder, Regionen und sogar Regionen zu unterteilen und dann abhängig von den Koordinaten des Benutzers zum gewünschten Diagramm umzuleiten. Dies machte es jedoch unmöglich, Routen zwischen Regionen zu legen, und vor allem löste es nicht die Notwendigkeit, alle diese Graphen im Speicher zu halten. Schließlich hat das einfache Kompilieren jedes solchen Objekts SEHR viele Ressourcen in Anspruch genommen und für immer gedauert. Zum Spaß habe ich auf meinem Computer (16 GB Frames) die Versammlung des Grafen von Frankreich gestartet, einen Tag gewartet und abgesagt.

Offensichtlich ist eine Technologie, die sich bei kleinen Aufgaben bewährt hat, überhaupt nicht für die Skalierung ausgelegt (zumindest nicht mit meinen Ressourcen). Es sollte also entweder eine Niederlage eingestehen oder zu einer anderen Technologie kriechen. Ich machte ein paar Tage Pause und begann zu untersuchen, welche anderen Open Source-Lösungen es auf der Welt gibt. Es stellte sich heraus, dass es im Grunde zwei davon gibt:


Wenn der erste in Java geschrieben ist und das Roadgraph in den Arbeitsspeicher lädt, ist OSRM - Open Source Routing Machine - bereits in Pluszeichen geschrieben und speichert seine (nicht weniger monströsen) Zwischendateien auf der Festplatte. Somit wurde die Notwendigkeit, eine große Menge an RAM zu haben, durch die Anforderung einer großen und schnellen Festplatte ersetzt. Das ist realer.

Ziellinie


Nach ein paar Nächten in der Dokumentation wurde der gesamte Servercode auf eine neue Lösung übertragen. Es hat wirklich funktioniert und es hat ziemlich gut funktioniert. Es war möglich, mehrere Länder miteinander zu verbinden, und sogar die Suchgeschwindigkeit wurde erhöht. Die allgemeinen Prinzipien waren dieselben: Aus dem OpenStreetMaps-Extrakt wurden Zwischendateien für das Profil „Maschine“ kompiliert (ein Profil ist eine Reihe von Gewichten und Anweisungen für Diagrammkanten - es gibt Profile „zu Fuß“, „Fahrrad“ usw.). Dann wurden diese Dateien in ein Verzeichnis gestellt, und die OSRM-API hat sie bereits von der Festplatte gelesen. Api erwies sich übrigens als ziemlich groß - sowohl Konturen als auch Routenplanung mit verschiedenen Nuancen wurden unterstützt, es wurden sogar Kacheln für die Karte generiert. Ich beschloss, mich näher mit letzterem zu befassen.

Als ich zur Anwendung zurückkehrte und sie weiter testete, erkannte ich noch ein paar Dinge:

  • Das Menü oben ist nicht gut, weit reichen
  • Die Übersichtskarte wird definitiv nicht benötigt, sie bindet mich nur an Google
  • Ergebniskarten sind langweilig und eintönig

Er warf glücklich eine Google-Karte aus (Hurra, jetzt 100% Open Source und seine Daten), vereinfachte das Menü und ging nach unten. Ich überlegte, was ich mit Karten anfangen sollte. Und dann tauchten Api-Kacheln sehr günstig auf, was ich oben erwähnt habe. Sie können eine Vektorkachel für die angegebenen Koordinaten und Zoomstufen erstellen. Das Ergebnis wird in Form eines binären Blobs vom Typ application / x-protobuf ausgegeben - ein Datentyp, der für die Manipulation eher unpraktisch ist. Ich werde nicht auf Details eingehen (ich musste ein wenig schwitzen), aber kurz gesagt, meine Handlungen sahen so aus:

  1. Nehmen Sie die Linie der konstruierten Route zum Punkt in Form einer Polylinie
  2. Polylinie -> GeoJSON
  3. Holen Sie sich den Begrenzungsrahmen dieser Form
  4. Fordern Sie alle von diesem Begrenzungsrahmen erfassten Kacheln an
  5. Konvertieren Sie Kacheldaten vom Binärformat in GeoJSON
  6. Fliesen kleben, durch Begrenzungsrahmen zuschneiden, mit der Routenlinie kombinieren, kolorieren
  7. Das resultierende GeoJSON wird in eine Bitmap konvertiert

Im Verlauf der Aktion gab es verschiedene Nuancen, z. B. das Einrücken des Begrenzungsrahmens oder das Markieren von Punkten mit farbigen Ringen (und das Konstantmachen des Radius für alle Zoomstufen). Das resultierende Bild sah folgendermaßen aus:



Feinschliff


Als ich jedem Ergebnis eine visuelle Route hinzufügte, begann die Liste mit neuen Farben zu funkeln. Als ich merkte, dass jedes Bild standardmäßig rittlings im Norden fährt, ließ ich sie sich in Bezug auf den Kompass drehen. Somit ist dieser Chip neben dem visuellen Effekt auch funktionsfähig geworden und ersetzt den Richtungspfeil. Jetzt, wo Sie fahren, können Sie sicher sehen, welche Seite von Ihnen dieses oder jenes Ergebnis ist.

Der dritte Entwicklungsmonat lief ab und es war bereits eine Abrundung erforderlich. Je mehr Sie hinzufügen, desto mehr möchten Sie. Irgendwann müssen Sie sich nur noch zusammenreißen und das Projekt loslassen. Ich habe die Benutzeroberfläche etwas weiter optimiert und bemalt und zur Vervollständigung das Anwendungslogo skizziert:



und Intro-Seite:



Und schließlich die endgültige Version der Anwendung:









Zusammenfassung


Danke fürs Zuschauen. Ich hoffe, dieser Strom des Bewusstseins wird für jemanden interessant und vielleicht sogar nützlich sein. Zu diesem Zeitpunkt denke ich, dass die Anwendung fertig ist: Sie ist schnell, ohne spezielle Fehler und kann in jedem Land der Welt funktionieren. Übrigens haben Sie vielleicht bemerkt, dass die Screenshots sowohl vom iPhone als auch von Android stammen, da die Anwendung dank Flutter auf beiden Plattformen genau gleich funktioniert.

Trotzdem habe ich mich bisher entschlossen, alles einzufrieren - habe meinen Job geändert, neue Bedenken sind aufgetaucht. Nach ein paar Monaten wischte ich den Staub ab und beschloss, eine Retrospektive zu schreiben. Ihre Bewertung ist interessant: Möchten Sie es, verwenden Sie es, was geändert werden kann.

PS : Über die Bereitschaft der Bewerbung ist natürlich Unsinn. Es ist als Prototyp fertig - wenn Sie sich einer ernsthaften Produktion nähern, müssen Sie Datensynchronisationsskripte mit OpenStreetMaps erstellen, den Betrieb im Zoo von Geräten überprüfen, Schnittstellen lokalisieren usw. Das gleiche Backend auf dem Knoten und Python wird ernsthaft belastet.

Source: https://habr.com/ru/post/de429240/


All Articles