Je suis allé à un entretien d'embauche d'ingénieur de données. L'enquêteur m'a posé une question. Il m'a donné une situation et m'a demandé de concevoir le flux de données pour ce système. J'ai résolu cela mais il n'a pas aimé ma solution et j'ai échoué. J'aimerais savoir si vous avez de meilleures idées pour résoudre ce défi.
La question était:
Notre système reçoit quatre flux de données. Les données contiennent un identifiant de véhicule, une vitesse et des coordonnées de géolocalisation. Chaque véhicule envoie ses données une fois par minute. Il n'y a aucun lien entre un flux spécifique et une route ou un véhicule spécifique ou toute autre chose. Il existe une fonction qui accepte les coordinations et renvoie un nom de section de route. Nous devons connaître la vitesse moyenne par tronçon de route toutes les 5 minutes. Enfin, nous voulons écrire les résultats à Kafka.
Ma solution était donc:
Tout d'abord, écrivez toutes les données dans un cluster Kafka, en un seul sujet, partitionné par les 5-6 premiers chiffres de la latitude concaténée aux 5-6 premiers chiffres de la longitude. Ensuite, lisez les données par Streamed Structuré, ajoutez pour chaque ligne le nom du tronçon de route par les coordinations (il y a un udf prédéfini pour cela), puis collez les données par nom de tronçon de route.
Parce que je partitionne les données dans Kafka par les 5-6 premiers chiffres des coordinations, après avoir traduit les coordinations en nom de section, il n'est pas nécessaire de transférer beaucoup de données vers la partition correcte et donc je peux profiter de l'opération colesce () cela ne déclenche pas un shuffle complet.
Calculer ensuite la vitesse moyenne par exécuteur.
L'ensemble du processus se déroulera toutes les 5 minutes et nous écrirons les données en mode ajout dans le récepteur Kafka final.
Encore une fois, l'intervieweur n'a pas aimé ma solution. Quelqu'un pourrait-il suggérer comment l'améliorer ou une idée complètement différente et meilleure?
Réponses:
J'ai trouvé cette question très intéressante et j'ai pensé à essayer.
Comme je l'ai évalué plus avant, votre tentative elle-même est bonne, à l'exception des suivantes:
Si vous avez déjà une méthode pour obtenir l'id / le nom de la section de route en fonction de la latitude et de la longitude, pourquoi ne pas appeler cette méthode en premier et utiliser l'id / nom de la section de route pour partitionner les données en premier lieu?
Et après cela, tout est assez facile, donc la topologie sera
(Des explications plus détaillées peuvent être trouvées dans les commentaires dans le code ci-dessous. Veuillez demander si quelque chose n'est pas clair)
J'ai ajouté le code à la fin de cette réponse, veuillez noter qu'au lieu de la moyenne, j'ai utilisé la somme car c'est plus facile à démontrer. Il est possible de faire la moyenne en stockant des données supplémentaires.
J'ai détaillé la réponse dans les commentaires. Voici un diagramme de topologie généré à partir du code (grâce à https://zz85.github.io/kafka-streams-viz/ )
Topologie:
la source
Le problème en tant que tel semble simple et les solutions proposées ont déjà beaucoup de sens. Je me demande si l'intervieweur était préoccupé par la conception et les performances de la solution sur laquelle vous vous êtes concentré ou par l'exactitude du résultat. Étant donné que d'autres se sont concentrés sur le code, la conception et les performances, je vais peser sur la précision.
Solution de streaming
Au fur et à mesure que les données circulent, nous pouvons fournir une estimation approximative de la vitesse moyenne d'une route. Cette estimation sera utile pour détecter la congestion mais sera désactivée pour déterminer la limite de vitesse.
Solution par lots
Cette estimation sera désactivée car la taille de l'échantillon est petite. Nous aurons besoin d'un traitement par lots sur des données de mois / trimestre / année entières pour déterminer plus précisément la limite de vitesse.
Lire les données d'une année de Data Lake (ou Kafka Topic)
Appliquez l'UDF sur les coordonnées pour obtenir le nom de la rue et le nom de la ville.
Calculez la vitesse moyenne avec une syntaxe comme -
Sur la base de cette limite de vitesse plus précise, nous pouvons prédire un trafic lent dans l'application de streaming.
la source
Je vois quelques problèmes avec votre stratégie de partitionnement:
Lorsque vous dites que vous allez partitionner vos données en fonction des 5 à 6 premiers chiffres de lat, vous ne pourrez pas déterminer le nombre de partitions kafka à l'avance. Vous aurez des données asymétriques car pour certaines sections de route vous observerez un volume élevé que d'autres.
De plus, votre combinaison de touches ne garantit pas les mêmes données de tronçon de route dans la même partition et vous ne pouvez donc pas être sûr qu'il n'y aura pas de mélange.
Les informations fournies par l'OMI ne sont pas suffisantes pour concevoir l'ensemble du pipeline de données. Parce que lors de la conception du pipeline, la façon dont vous partitionnez vos données joue un rôle important. Vous devriez vous renseigner davantage sur les données que vous recevez comme le nombre de véhicules, la taille des flux de données d'entrée, le nombre de flux est-il fixe ou peut-il augmenter à l'avenir? Les flux de données d'entrée que vous recevez sont-ils des flux kafka? Combien de données vous recevez en 5 minutes?
mapValues
etreduceByKey
au lieu de groupBy. Référez ceci .la source
mapValues
etreduceBy
appartient en effet à un RDD de bas niveau, mais il fonctionnera toujours mieux dans cette situation car il calculera d'abord l'agrégat par partition, puis effectuera le brassage.Les principaux problèmes que je vois avec cette solution sont:
Je dirais que la solution doit faire: lire à partir du flux Kafka -> UDF -> tronçon de route groupby -> moyen -> écrire dans le flux Kafka.
la source
Ma conception dépendrait de
Si je veux évoluer pour un certain nombre de comptes, la conception ressemblerait à ceci
Croiser les inquiétudes sur cette conception -
Quelques améliorations pratiques possibles sur cette conception -
la source