Ich ging zu einem Vorstellungsgespräch als Dateningenieur. Der Interviewer hat mir eine Frage gestellt. Er gab mir eine Situation und bat mich, den Datenfluss für dieses System zu entwerfen. Ich habe das gelöst, aber er mochte meine Lösung nicht und ich habe versagt. Ich würde gerne wissen, ob Sie bessere Ideen haben, wie Sie diese Herausforderung lösen können.
Die Frage war:
Unser System empfängt vier Datenströme. Die Daten enthalten eine Fahrzeug-ID, Geschwindigkeit und Geolokalisierungskoordinationen. Jedes Fahrzeug sendet seine Daten einmal pro Minute. Es gibt keine Verbindung zwischen einem bestimmten Strom und einer bestimmten Straße, einem bestimmten Fahrzeug oder etwas anderem. Es gibt eine Funktion, die Koordinationen akzeptiert und einen Straßenabschnittnamen zurückgibt. Wir müssen die durchschnittliche Geschwindigkeit pro Straßenabschnitt pro 5 Minuten kennen. Zum Schluss wollen wir die Ergebnisse an Kafka schreiben.
Meine Lösung war also:
Schreiben Sie zuerst alle Daten in einen Kafka-Cluster, in ein Thema, unterteilt durch die 5-6 ersten Ziffern des Breitengrads, verkettet mit den 5-6 ersten Ziffern des Längengrads. Lesen Sie dann die Daten durch strukturiertes Streaming, fügen Sie für jede Zeile den Namen des Straßenabschnitts durch die Koordinationen hinzu (dafür gibt es ein vordefiniertes udf) und fassen Sie die Daten dann nach dem Namen des Straßenabschnitts zusammen.
Da ich die Daten in Kafka nach den 5-6 ersten Ziffern der Koordinationen partitioniere, müssen nach der Übersetzung der Koordinationen in den Abschnittsnamen nicht viele Daten auf die richtige Partition übertragen werden, und daher kann ich die Operation colesce () nutzen das löst kein vollständiges Mischen aus.
Berechnen Sie dann die Durchschnittsgeschwindigkeit pro Executor.
Der gesamte Vorgang wird alle 5 Minuten ausgeführt und die Daten werden im Append-Modus in die endgültige Kafka-Senke geschrieben.
Also wieder, der Interviewer mochte meine Lösung nicht. Könnte jemand vorschlagen, wie man es verbessern kann oder eine ganz andere und bessere Idee?
Antworten:
Ich fand diese Frage sehr interessant und dachte darüber nach, es zu versuchen.
Wie ich weiter ausgewertet habe, ist Ihr Versuch selbst gut, mit Ausnahme der folgenden:
Wenn Sie bereits eine Methode haben, um die ID / den Namen des Straßenabschnitts basierend auf Breite und Länge zu ermitteln, rufen Sie diese Methode zuerst auf und verwenden Sie die ID / den Namen des Straßenabschnitts, um die Daten überhaupt zu partitionieren.
Und danach ist alles ganz einfach, also wird die Topologie sein
(Eine ausführlichere Erklärung finden Sie in den Kommentaren im Code unten. Bitte fragen Sie, ob etwas unklar ist.)
Ich habe den Code am Ende dieser Antwort hinzugefügt. Bitte beachten Sie, dass ich anstelle des Durchschnitts die Summe verwendet habe, da dies einfacher zu demonstrieren ist. Es ist möglich, einen Durchschnitt zu erstellen, indem einige zusätzliche Daten gespeichert werden.
Ich habe die Antwort in Kommentaren detailliert beschrieben. Es folgt ein Topologiediagramm, das aus dem Code generiert wurde (dank https://zz85.github.io/kafka-streams-viz/ ).
Topologie:
quelle
Das Problem als solches scheint einfach zu sein und die angebotenen Lösungen sind bereits sehr sinnvoll. Ich frage mich, ob der Interviewer besorgt über das Design und die Leistung der Lösung war, auf die Sie sich konzentriert haben, oder über die Genauigkeit des Ergebnisses. Da sich andere auf Code, Design und Leistung konzentriert haben, werde ich die Genauigkeit abwägen.
Streaming-Lösung
Während die Daten einfließen, können wir eine grobe Schätzung der Durchschnittsgeschwindigkeit einer Straße liefern. Diese Schätzung ist hilfreich bei der Erkennung von Überlastungen, bei der Bestimmung der Geschwindigkeitsbegrenzung jedoch nicht.
Chargenlösung
Diese Schätzung ist deaktiviert, da die Stichprobengröße klein ist. Wir benötigen eine Stapelverarbeitung für ganze Monat / Quartal / Jahr-Daten, um das Tempolimit genauer zu bestimmen.
Lesen Sie die Daten eines Jahres vom Datensee (oder Kafka-Thema).
Wenden Sie UDF auf Koordinaten an, um den Straßennamen und den Städtenamen zu erhalten.
Berechnen Sie die Durchschnittsgeschwindigkeit mit einer Syntax wie -
Basierend auf dieser genaueren Geschwindigkeitsbegrenzung können wir langsamen Verkehr in der Streaming-Anwendung vorhersagen.
quelle
Ich sehe einige Probleme mit Ihrer Partitionierungsstrategie:
Wenn Sie sagen, dass Sie Ihre Daten basierend auf den ersten 5-6 Ziffern Lat-Länge partitionieren möchten, können Sie die Anzahl der Kafka-Partitionen nicht im Voraus bestimmen. Sie haben verzerrte Daten, da Sie bei einigen Straßenabschnitten ein höheres Volumen als bei anderen beobachten.
Und Ihre Tastenkombination garantiert ohnehin nicht dieselben Straßenabschnittsdaten in derselben Partition, und daher können Sie nicht sicher sein, dass kein Mischen stattfindet.
IMO-Informationen reichen nicht aus, um die gesamte Datenpipeline zu entwerfen. Denn beim Entwerfen der Pipeline spielt die Partitionierung Ihrer Daten eine wichtige Rolle. Sie sollten sich mehr über die Daten erkundigen, die Sie erhalten, z. B. Anzahl der Fahrzeuge, Größe der Eingabedatenströme, Ist die Anzahl der Datenströme festgelegt oder kann sie in Zukunft zunehmen? Sind die Eingangsdatenströme, die Sie empfangen, Kafka-Ströme? Wie viele Daten erhalten Sie in 5 Minuten?
mapValues
undreduceByKey
anstelle von groupBy verwenden. Verweisen Sie darauf .quelle
mapValues
undreduceBy
gehört zwar zu Low-Level-RDD, wird aber in dieser Situation immer noch eine bessere Leistung erbringen, da zuerst das Aggregat pro Partition berechnet und dann gemischt wird.Die Hauptprobleme, die ich bei dieser Lösung sehe, sind:
Ich würde sagen, die Lösung muss Folgendes tun: Lesen aus dem Kafka-Stream -> UDF -> Gruppieren nach Straßenabschnitten -> Durchschnitt -> Schreiben in den Kafka-Stream.
quelle
Mein Design würde davon abhängen
Wenn ich für eine beliebige Anzahl von Zählungen skalieren möchte, würde das Design so aussehen
Cross Bedenken zu diesem Design -
Einige praktische Verbesserungen an diesem Design möglich -
quelle