Wie ich versucht habe, die Suche auf den Karten nach Fahrern zu korrigieren

Dies ist eine Geschichte darüber, wie ich versuchte, ein seltsames Problem zu lösen, das mich daran hinderte, es selbst zu tun. Mit Blick auf die Zukunft werde ich sagen - ich bin mit der daraus resultierenden Entscheidung zufrieden und habe die Bewerbung zu ihrem logischen Ende gebracht. Um es jedoch vollständig ausführen zu können, benötigen Sie mehr Ressourcen. Deshalb entschied ich mich, eine Pause einzulegen und die Leute zu fragen, ob sie von jemand anderem benötigt werden. Zu diesem Zweck (und auch nur zum Sprechen) und hier schreiben.

Zwei Worte über mich: Ich wohne in Dublin, Irland, und arbeite als Programmierer. Es ist nicht genau an Ort und Stelle, also habe ich in meiner Freizeit verschiedene Projekte zu Hause gesehen, meistens am Tisch. Auf Habré schreibe ich zum ersten Mal, obwohl ich seit vielen Jahren lese.

Das Problem


Vor langer Zeit, als ich auf der Arbeit viel zu unbekannten Orten reisen musste, bemerkte ich, dass die Standardsuche auf Karten heutzutage für den Fahrer absolut nicht anwendbar ist. Schau mal: Du fährst an einem unbekannten Ort hinter dem Lenkrad und hast einen Benzinpfeil bei Null. Deine Handlungen? Wenn ich in diesem Moment nicht alleine im Auto bin, dann sage ich dem Passagier: "Schauen Sie sich die Tankstelle an, während ich unterwegs bin". Wenn Sie es selbst tun, müssen Sie die folgenden Aktionen ausführen:

  1. Zu stoppen
  2. Geben Sie in der Kartenanwendung bei der Suche "Benzin" ein (oder klicken Sie auf eine der Schnelltasten, die einige Karten jetzt bieten).
  3. Die Anwendung führt eine Suche aus und zeigt Ihnen eine riesige Karte mit einem Dutzend Nachfüllungen
  4. Sie versuchen herauszufinden, welcher Ihnen am nächsten ist, und klicken Sie darauf, um eine Route zu erstellen.

Meiner Meinung nach ein Albtraum. Zuerst muss man anhalten oder zumindest auf die Ampel warten. Weil die Karten komplex sind und die Symbole klein sind. Zweitens sagt die Karte nicht, was die nächste Tankstelle ist. In dieser Hinsicht ist Google das Schlimmste: Selbst in den Ergebnissen in Form einer Liste drängt er störrisch nicht den nächstgelegenen Platz nach oben, aber ich habe keine Ahnung, was am besten bewertet wird / mit Fotos / bezahlt /.



Nun, der dritte Faktor: Wir bewegen uns. Das Ergebnis, das die Karten ausstellten, war für einen bestimmten Punkt relevant, aber wir sind schon weit davon entfernt. Ist Ihnen aufgefallen, dass selbst die von Google geplante Route nicht automatisch aktualisiert wird, wenn wir verschoben werden? Nur wenn die Navigation bereits gestartet wurde, wird sie neu aufgebaut.

Im Allgemeinen ist das Problem klar. Logik, die für Fußgänger und ihre Bedürfnisse funktioniert, für Autofahrer nichts. Ich interessiere mich nicht für die Bewertung des Ortes und welche Art von Küche es gibt - ich brauche, ohne von der Straße abgelenkt zu werden, in Echtzeit, um eine Route zur nächsten Tankstelle, zum Aufladen, zum Parken, zum Geldautomaten usw. zu bekommen.

Idee


Lassen Sie uns nun versuchen, das ideale Suchskript zu ermitteln. Die folgenden Kriterien

  • Die Interaktion ist kurz und verständlich, um den Fahrer nicht abzulenken
  • transparente entfernungsbasierte Lieferung
  • Echtzeit-Update

Als erstes empfiehlt es sich, die einmalige Standard-Suche durch einen Scan zu ersetzen. Das heißt, eine Aktionskette ist ungefähr wie folgt:

  1. Führen Sie einen Scan aus
  2. Sie gehen, Sie sehen die aktualisierten Ergebnisse in Echtzeit
  3. Wenn mir etwas gefiel, habe ich die Route angeklickt und gepflastert.

Sie legen die Suchkriterien im Voraus fest. Dies ist der Ortstyp und der Scan-Radius. Während sich das Auto bewegt, funktioniert die Anwendung außerdem als Radar. Schnell wurde klar, dass der Radius nicht rund war, sondern in Form einer Isoline. Zweitens sollte es nicht nach Entfernung, sondern nach Zeit gebaut werden, da Minuten für die Wahrnehmung viel einfacher sind als Kilometer.

Dann dachte ich über die Art der Ergebnisausgabe nach. 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 großen Text und große Tasten. Daher entschied ich sofort, dass der Hauptbildschirm eine Liste sein würde, und ich könnte zuerst eine Karte hinzufügen und sehen, ob ich sie verlassen habe.

Planen


Ich kannte meine Besonderheit, Projekte zu dehnen, und entschied mich für 2 Monate für mich - als Ergebnis kam ich zu 3. Grundsätzlich ist die Anwendung recht einfach:

  1. Ein Client eines Bildschirmpaares (Suche, Liste und Karte)
  2. Sendet regelmäßig die Koordinaten, den Suchradius und den Typ der Orte an den Server
  3. Der Server erstellt die Isoline rechtzeitig (übrigens hat ihren Namen auf Englisch - Isochrone), führt eine Suche an Orten durch und gibt eine Liste zurück

Klingt nach einer Lunge leichter. Ich hatte bereits Erfahrung in der Kartografie (vor einigen Jahren habe ich ein Immobilienportal erstellt, auf dem die Suche auf der Karte durchgeführt wurde). Der Stack im Backend war also sofort klar:

  • Importieren von Daten aus OpenStreetMaps in Elasticsearch
  • OpenTripPlanner zum Konturieren

Beim Nachdenken entschied ich mich auf dem Client für das neue Google-Framework - Flutter. Es ist plattformübergreifend, ziemlich flexibel und ermöglicht es Ihnen, vollwertige Anwendungen mit einem Minimum an Code zu erstellen. Natürlich ist es roh und unverständlich in der Produktion, sieht aber perfekt für das Prototyping aus. Es ist notwendig zu klären, dass ich zu diesem Zeitpunkt bereits die Erfahrung der nativen Entwicklung für Android hatte (war der Teamleiter) und beschloss, sozusagen dem Feind ins Gesicht zu schauen. Der Feind war nicht so schrecklich.

Umsetzung


Der erste Prototyp der Anwendung war sehr schnell fertiggestellt - Flutter hat eine niedrige Einstiegsschwelle und eine verständliche Redux-ähnliche Philosophie. Die deklarative Beschreibung der Schnittstellen hat seltsamerweise auch gefallen, ebenso wie der heiße Neustart (React Native, Ihre Karte ist ein bisschen). Im Allgemeinen schienen die Google-Nutzer die meisten angeborenen Krankheiten der vorangegangenen Versuche zu berücksichtigen. Ich verstehe jedoch Menschen, die möglicherweise nicht alles haben - Jemand mag keine Darts, eine begrenzte Anzahl von Widgets und der hier angebotene "visuelle Debugging" ist etwas sehr Rohes.

Im Backend habe ich folgendes gemacht:

  1. Ich habe Nominatim, gefülltes OpenStreetMaps-Datenextrakt, in seine Datenbank aufgenommen (ich habe es hier genommen ), und zwar mit seinem nativen Dienstprogramm osm2pgsql. Warum haben Sie sich für Photon entschieden , einen kleinen, aber sehr angenehmen Open Source-Geocoder . Früher habe ich es in einigen Projekten verwendet - es generiert den Elasticsearch-Index, importiert Daten aus der Nominatim-Datenbank und sucht nach diesem Index. Ich mag es mit Geschwindigkeit und sauberem Mapping (zum Beispiel habe ich Pelias ausprobiert und es hat mir weniger gefallen). Sein Hauptproblem ist die alte Version von elastisch, aber in meinem Fall brauchte ich nicht die Funktionalität des Geocoders selbst, sondern nur die Daten. Nach dem Importieren habe ich den Index mit einer reinen Seele auf die neueste Version der elastischen Installation übertragen. Warum habe ich übrigens Elasticsearch gewählt? Es ist sehr schnell und hat die Funktion, Koordinaten nach Polygonen zu finden.
  2. Polygon - es ist isochron - für mich zunächst OpenTripPlanner generiert . Dies ist ein guter Open Source Routenplaner. Es funktioniert wie folgt: Es nimmt den gleichen Auszug aus OpenStreetMaps und kompiliert es zu einem großen Diagramm von Straßen, das als separates Objekt auf der Festplatte gespeichert wird. Beim Start des Servers wird diese Grafik in den RAM geladen und alle Routen werden durchsucht. Vorteile: Schnelle Erhöhung, reichhaltige Funktionalität (z. B. Erzeugen von Isolinien aus der Box) und gute Arbeitsgeschwindigkeit. Nachteile: Diese Arbeitsgeschwindigkeit hängt direkt von der Größe des Arbeitsspeichers ab und die Dokumentation ist äußerst ekelhaft. Nur monströse Dokumentation. Vietnamesische Rückblenden.
  3. Auf dem Python habe ich eine kleine API entworfen, die den Platztyp und den Suchradius in Sekunden einnimmt, das Polygon von OpenTripPlanner anfordert und dann in Elasticsearch danach sucht. Für jeden gefundenen Ort fordert er eine Route (erneut von OpenTripPlanner) an, 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 Gerätekoordinaten um 5 Meter verschoben habe. Die Karte ist statisch - ich habe gerade Google-Karten von Google verwendet (wie Sie sehen können, ist dies der einzige Ort, an dem das Unternehmen in unsere gemütliche Welt gekommen ist). Die erste Implementierung sah folgendermaßen aus:





 Nachdem ich

mit der Anwendung gespielt hatte, entschied ich mich, die Karte auszublenden. Sie hat gut verstanden, welche Suchseite erstellt wurde, und sie sah unterhaltsam aus - es war interessant zu sehen, wie sich dieser Krake in Echtzeit verändert. Diese Unterhaltung half der Anwendung jedoch nicht bei der Ausführung ihrer Funktionen und belegte ein Drittel des Bildschirms.

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

  1. Wir erinnern uns an unsere vorherigen Koordinaten
  2. Bei Offset zeichnen wir die Route von der vorherigen Position zur aktuellen.
  3. Wir nehmen den letzten Abschnitt unserer Route und vergleichen ihn mit dem ersten Abschnitt der Route jedes Ergebnisses. Da sie auf demselben Straßennetz liegen, liegt der Winkel zwischen ihnen mit einer Wahrscheinlichkeit von 99% nahe bei 0 oder 180.

Dieser sehr einfache Trick macht es viel einfacher zu verstehen, ob wir uns bereits einem Ort zuwenden oder uns umdrehen müssen.



Zu dieser Zeit war ich mit der resultierenden Anwendung sehr zufrieden und habe mich entschlossen, sie in mehreren Ländern einzusetzen. Dennoch ist Irland ein sehr kleiner Staat, und der elastische Index und das Diagramm der Straßen waren klein. Für den Test entschied ich mich, das benachbarte UK anzuschließen. Es ist etwa viermal länger und hat ein viel dichteres Straßennetz (insbesondere die Hauptstadt und die Großstädte). Und es gab ein Problem.

Elasticsearch hat den erhöhten Index erwartungsgemäß gut verdaut, aber mit OpenTripPlanner ist ein vollständiger Fehler aufgetreten. Es ist in Java geschrieben und generiert, wie gesagt, eine grafische Darstellung der Straßen, so dass diese nach dem Laden in den RAM-Speicher geladen wird. Die Anzahl für Irland betrug 1 Gigabyte, für Großbritannien waren es bereits 5. Sie können natürlich in Länder, Regionen und sogar Gebiete einbrechen und dann je nach den Koordinaten des Benutzers zum gewünschten Graphen umleiten. Dies machte es jedoch unmöglich, Routen zwischen den Bereichen zu erstellen, und vor allem löste er nicht die Notwendigkeit aus, alle diese Graphen im Speicher zu halten. Das einfache Kompilieren jedes dieser Objekte beanspruchte SEHR Ressourcen und dauerte ewig. Bei Interesse begann ich die Montage des Grafen von Frankreich in meinem Auto (16 GB-Rahmen), wartete 24 Stunden und stornierte.

Es ist offensichtlich, dass die Technologie, die sich in kleinen Aufgaben gut bewährt hat, absolut nicht für die Skalierung konzipiert ist (zumindest nicht mit meinen Ressourcen). Man sollte sich also entweder geschlagen geben oder zu einer anderen Technologie krabbeln. 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 die erste in Java geschrieben ist und den Graphen der Straßen in den RAM lädt, ist OSRM - die Open Source Routing Machine - bereits auf den Profis geschrieben und speichert ihre (nicht weniger monströsen) Zwischendateien auf der Festplatte. Daher hat sich die Notwendigkeit einer großen Menge an RAM zur Anforderung einer großen und schnellen Festplatte geändert. Das ist schon realer.

Ziellinie


Nach ein paar Nächten des Bastelns der Dokumentation wurde der gesamte Servercode in eine neue Lösung übertragen. Es hat wirklich funktioniert, und es hat gut funktioniert. Es war möglich, mehrere Länder miteinander zu verbinden, und sogar die Suchgeschwindigkeit erhöhte sich. Die allgemeinen Prinzipien waren die gleichen: Aus dem Auszug von OpenStreetMaps wurden Zwischendateien für das Profil "Maschine" erstellt (das Profil enthält eine Gruppe von Gewichten und Anweisungen für die Kanten der Grafik - es gibt "Fuß", "Fahrrad" usw.). Dann wurden diese Dateien zu dem Verzeichnis hinzugefügt, und OSRM-APIs lesen sie bereits von der Festplatte. Übrigens erwies sich Api als ziemlich groß - sowohl die Höhenlinien als auch das Routen mit verschiedenen Nuancen wurden unterstützt, es gab sogar eine Reihe von Kacheln für die Karte. Zum Schluss habe ich mich entschieden, genauer anzuhalten.

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

  • Die Speisekarte oben ist nicht gut
  • Ich brauche keine gemeinsam genutzte Karte, sie bindet mich einfach an Google
  • Ergebniskarten langweilig und eintönig

Gerne warf ich eine Google-Karte (Hurra, jetzt zu 100% Open Source und meine Daten) aus, vereinfachte das Menü, verschob es nach unten. Ich fing an zu überlegen, was ich mit den Karten anfangen sollte. Und hier sind übrigens die api-Kacheln aufgedreht, die ich oben erwähnt habe. Sie können damit eine Vektorkachel für die angegebenen Koordinaten und die Zoomstufe erzeugen. Das Ergebnis wird in Form eines binären Blobs vom Typ application / x-protobuf angegeben - ein recht ungünstiger Datentyp für Manipulationen. Ich werde nicht ins Detail gehen (ich musste ein wenig schwitzen), aber kurz gesagt sah mein Verhalten so aus:

  1. Nehmen Sie die Linie der konstruierten Route bis zum Punkt in Form einer Polylinie auf
  2. Polylinie -> GeoJSON
  3. Holen Sie sich den Begrenzungsrahmen dieser Form.
  4. Fordern Sie alle Kacheln an, die dieser Begrenzungsrahmen erfasst
  5. Konvertieren Sie Tile-Daten vom Binärformat in GeoJSON
  6. Fliesen verkleben, entlang des Begrenzungsrahmens zuschneiden, mit der Routenlinie kombinieren, streichen
  7. Aus GeoJSON wurde ein Rasterbild

Im Verlauf der Aktion gab es unterschiedliche Nuancen, z. B. das Einrasten eines Begrenzungsrahmens oder das Markieren von Punkten mit farbigen Ringen (und der Radius aller Zoomstufen ist konstant). Das resultierende Bild sah so aus:



Die letzten Schliffe


Nachdem ich jedem Ergebnis eine visuelle Route hinzugefügt hatte, begann die Liste mit neuen Farben zu spielen. Als ich feststellte, dass jedes Bild im Norden voreingestellt ist, habe ich sie in Bezug auf den Kompass gedreht. Neben dem visuellen Effekt wurde auch dieser Chip funktional - der Richtungspfeil wurde ersetzt. Wenn Sie sich nun hinter dem Rad bewegen, können Sie genau sehen, welche Seite von Ihnen oder welches andere Ergebnis sich befindet.

Der dritte Monat der Entwicklung lief ab, und es war bereits notwendig, abzurunden. Je mehr Sie hinzufügen, desto mehr wollen Sie, also müssen Sie sich irgendwann zusammenreißen und das Projekt freigeben. Ich habe das Interface ein wenig mehr korrigiert und bemalt, und für das Gefühl der Fertigstellung habe ich das Anwendungslogo entworfen:



und die Einführungsseite:



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









Das Ergebnis


Vielen Dank für Ihre Aufmerksamkeit. Ich hoffe, dass dieser Bewusstseinsstrom für jemanden interessant und vielleicht sogar nützlich ist. In diesem Stadium halte ich die Anwendung für bereit: Sie ist schnell, ohne besondere Fehler und kann in jedem Land der Welt arbeiten. Übrigens haben Sie vielleicht bemerkt, dass die Screenshots sowohl vom iPhone als auch vom Android stammen, denn dank Flutter funktioniert die Anwendung auf beiden Plattformen genau gleich.

Trotzdem habe ich mich entschlossen, alles einzufrieren - ich habe den Job gewechselt, neue Bedenken kamen auf. Nach ein paar Monaten schüttelte ich den Staub ab und beschloss, eine Retrospektive zu schreiben. Ihr Feedback ist interessant: Ob Sie es wünschen, verwenden, was kann geändert werden.

PSNatürlich ist über die Bereitschaft der Bewerbung Unsinn. Es ist als Prototyp fertig - wenn Sie sich einer ernsthaften Produktion nähern, müssen Sie Datensynchronisationsskripts mit OpenStreetMaps ausführen, die Arbeit auf den Zoogeräten überprüfen, Schnittstellen lokalisieren und so weiter. Das gleiche Backend für den Knoten und Python fällt unter jede ernsthafte Last.

Jetzt auch beliebt: