Kafka Streams窗口如何工作?

时间:2018-05-31 12:54:32

标签: apache-kafka-streams ksql

我很难理解Windowing在Kafka Streams中是如何工作的。结果似乎与我到目前为止所阅读和理解的内容一致。

我创建了一个带有支持主题的KSQL Stream。其中一个'列'在KSQL SELECT语句中已被指定为该主题的TIMESTAMP。

CREATE STREAM my_stream WITH (KAFKA_topic='my-stream-topic', VALUE_FORMAT='json', TIMESTAMP='recorded_timestamp') AS select <select list> PARTITION BY PARTITION_KEY;

my-stream-topic中的记录按键(PARTITION_KEY)分组,并使用跳跃窗口加窗

val dataWindowed: TimeWindowedKStream[String, TopicValue] = builder.stream('my-stream-topic', consumed) 
    .groupByKey(Serialized.`with`(Serdes.String(), valueSerde))
    .windowedBy(TimeWindows.`of`(TimeUnit.MINUTES.toMillis(5)).advanceBy(TimeUnit.MINUTES.toMillis(1)).until(TimeUnit.MINUTES.toMillis(5)))

记录通过

汇总
val dataAgg: KTable[Windowed[String], ValueStats] = dataWindowed
    .aggregate(
      new Initializer[TopicStats] {<code omitted>}},
      new Aggregator[String, TopicValue, TopicStats] {<code omitted>}},
      Materialized.`as`[String, TopicStats, WindowStore[Bytes, Array[Byte]]]("time-windowed-aggregated-stream-store")
        .withValueSerde(new JSONSerde[TopicStats])
    )

  val topicStats: KStream[String, TopicValueStats] = dataAgg
    .toStream()
    .map( <code omitted for brevity>)

然后我通过

打印到控制台
dataAgg.print()
topicStats.print()

该组中的第一个窗口转换为7:00 - 7:05

当我通过控制台消费者检查my-stream-topic中的记录时,我发现有2条记录应该属于上述窗口。但是,聚合器只能选择其中一个。

我认为dataAgg窗口化KTable将包含分组密钥的1条记录,但聚合将使用2条记录来计算聚合。打印的总值不正确。

我错过了什么?

1 个答案:

答案 0 :(得分:2)

KSQL可以在写入时设置记录时间戳,但是您需要在创建输入流时指定时间戳,而不是在定义输出流时。即,为输入流指定的时间戳将用于在写入时设置记录元数据字段。

这种行为相当不直观,我为此问题开了一张票:https://github.com/confluentinc/ksql/issues/1367

因此,在为问题中显示的查询创建输入流时,需要指定with(TIMESTAMP='recorded_timestamp')子句。如果这不可能,因为您的查询需要在不同的时间戳上运行,您需要指定将数据复制到新主题的第二个查询。

CREATE STREAM my_stream_with_ts
    WITH (KAFKA_topic='my-stream-topic-with-ts')
AS select * from my_stream PARTITION BY PARTITION_KEY;

作为替代方案,您可以为Kafka Streams应用程序设置自定义时间戳提取器,以从有效负载中提取时间戳。