Ce que j'aimerais faire, c'est ceci:
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?
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.
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.