web-dev-qa-db-fra.com

Comment envoyer le résultat final de l'agrégation de flux kafka d'un KTable à fenêtre temporelle?

Ce que j'aimerais faire, c'est ceci:

  1. Consommer des enregistrements à partir d'un sujet de nombres (Long)
  2. Agréger (compter) les valeurs pour chaque fenêtre de 5 secondes
  3. Envoyer le résultat d'agrégation FINAL à un autre sujet

Mon code ressemble à ceci:

KStream<String, Long> longs = builder.stream(
        Serdes.String(), Serdes.Long(), "longs");

// In one ktable, count by key, on a five second tumbling window.
KTable<Windowed<String>, Long> longCounts = 
        longs.countByKey(TimeWindows.of("longCounts", 5000L));

// Finally, sink to the long-avgs topic.
longCounts.toStream((wk, v) -> wk.key())
        .to("long-counts");

Il semble que tout fonctionne comme prévu, mais les agrégations sont envoyées à la rubrique de destination pour chaque enregistrement entrant. Ma question est de savoir comment puis-je envoyer uniquement le résultat d'agrégation final de chaque fenêtre?

28
odavid

Dans Kafka Streams, il n'y a rien de tel qu'une "agrégation finale". Windows est maintenu ouvert tout le temps pour gérer les enregistrements en panne qui arrivent après la fin de la fenêtre. Cependant , les fenêtres ne sont pas conservées indéfiniment. Elles sont supprimées une fois leur durée de conservation expirée. Il n'y a aucune action spéciale quant au moment où une fenêtre est supprimée.

Voir la documentation de Confluent pour plus de détails: http://docs.confluent.io/current/streams/

Ainsi, pour chaque mise à jour d'une agrégation, un enregistrement de résultat est généré (car Kafka Les flux mettent également à jour le résultat de l'agrégation sur les enregistrements hors service). Votre "résultat final" serait le dernier enregistrement des résultats (avant qu'une fenêtre ne soit supprimée). Selon votre cas d'utilisation, la déduplication manuelle serait un moyen de résoudre le problème (en utilisant l'API du levier inférieur, transform() ou process())

Ce billet de blog pourrait également aider: https://timothyrenner.github.io/engineering/2016/08/11/kafka-streams-not-looking-at-facebook.html

Un autre article de blog traitant de ce problème sans utiliser de signes de ponctuation: http://blog.inovatrend.com/2018/03/making-of-message-gateway-with-kafka.html

Mise à jour

Avec KIP-328 , un opérateur KTable#suppress() est ajouté, qui permettra de supprimer les mises à jour consécutives de manière stricte et d'émettre un seul enregistrement de résultat par fenêtre; le compromis est une latence accrue.

24
Matthias J. Sax

Depuis Kafka Streams version 2.1, vous pouvez y parvenir en utilisantsuppress.

Il y a un exemple de la documentation Apache Kafka Streams mentionnée qui envoie une alerte lorsqu'un utilisateur a moins de trois événements en une heure:

KGroupedStream<UserId, Event> grouped = ...;
grouped
  .windowedBy(TimeWindows.of(Duration.ofHours(1)).grace(ofMinutes(10)))
  .count()
  .suppress(Suppressed.untilWindowCloses(unbounded()))
  .filter((windowedUserId, count) -> count < 3)
  .toStream()
  .foreach((windowedUserId, count) -> sendAlert(windowedUserId.window(), windowedUserId.key(), count));

Comme mentionné dans la mise à jour de la réponse this , vous devez être conscient du compromis. De plus, note qui supprime () est basé sur l'heure de l'événement.

0