web-dev-qa-db-ja.com

時間枠付きKTableの最終的なkafka-streams集計結果を送信する方法は?

私がやりたいのはこれです:

  1. 数値トピックのレコードを消費する(ロング)
  2. 5秒ごとに値を集計(カウント)します
  3. FINAL集計結果を別のトピックに送信します

私のコードは次のようになります。

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");

すべてが期待どおりに機能するように見えますが、集計は各着信レコードの宛先トピックに送信されます。私の質問は、各ウィンドウの最終的な集計結果のみを送信するにはどうすればよいですか?

28
odavid

In Kafka Streamsには「最終的な集約」などはありません。ウィンドウは、ウィンドウの終了時間が経過した後に到着する順不同レコードを処理するために常に開いています。 、ウィンドウは永久に保持されるわけではありません。保持時間が経過すると破棄されます。

詳細については、Confluentのドキュメントを参照してください。 http://docs.confluent.io/current/streams/

したがって、集計の更新ごとに、結果レコードが生成されます(Kafka Streamsは順序が狂ったレコードの集計結果も更新するため)。「最終結果」が最新になります)結果レコード(ウィンドウが破棄される前)。ユースケースに応じて、手動の重複排除が問題を解決する方法になります(下位レバーAPI、transform()またはprocess()を使用)

このブログ投稿も役立つかもしれません: https://timothyrenner.github.io/engineering/2016/08/11/kafka-streams-not-looking-at-facebook.html

句読点を使用せずにこの問題に対処する別のブログ投稿: http://blog.inovatrend.com/2018/03/making-of-message-gateway-with-kafka.html

更新

KIP-328 を使用すると、KTable#suppress()演算子が追加されます。これにより、厳密な方法で連続した更新を抑制し、ウィンドウごとに単一の結果レコードを発行できます。トレードオフは遅延の増加です。

24
Matthias J. Sax

Kafka= Streamsバージョン2.1から、これを実現できます singsuppress

前述のApache Kafkaユーザーが1時間に3つ未満のイベントを持っている場合にアラートを送信するStreamsのドキュメントからの例があります。

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));

this answerの更新で述べたように、トレードオフに注意する必要があります。さらに、 suppress()はイベント時間に基づいています。