我有2个数据流,我希望能够加入他们一个月的窗口,让我们说。当我有实时数据时,使用 KStream 和加入,一切都很有趣且非常简单。我做了类似的事情;
KStream<String, GenericRecord> stream1 =
builder.stream(Serdes.String(), new CustomizeAvroSerde<>(this.getSchemaRegistryClient(), this.getKafkaPropsMap()), getKafkaConsumerTopic1());
KStream<String, GenericRecord> stream2 =
builder.stream(Serdes.String(), new CustomizeAvroSerde<>(this.getSchemaRegistryClient(), this.getKafkaPropsMap()), getKafkaConsumerTopic2());
long joinWindowSizeMs = 30L * 24L * 60L * 60L * 1000L; // 30 days
KStream<String, GenericRecord> joinStream = stream1.join(stream2,
new ValueJoiner<GenericRecord, GenericRecord, GenericRecord>() {
@Override
public GenericRecord apply(GenericRecord genericRecord, GenericRecord genericRecord2) {
final GenericRecord jonnedRecord = new GenericData.Record(jonnedRecordSchema);
....
....
....
return jonnedRecord;
}
}, JoinWindows.of(joinWindowSizeMs));
当我想要重播数据时,会出现问题。让我们说我想重新为我过去6个月的数据重新加入这些数据,因为我一次运行所有数据的管道kafkaStream将加入所有可连接数据并且它不会时间差考虑(它应该只加入一个月的数据)。我假设JoinWindow时间是我们将数据插入Kafka主题的时间,我是对的吗? 我怎样才能更改和操作这段时间,以便我可以正确地运行我的数据重播,我的意思是重新插入过去6个月的数据,每个相应的记录需要一个月的窗口,并加入一个。
这个问题与How to manage Kafka KStream to Kstream windowed join?没有重复,在那里我问我怎样才能根据时间窗口加入。我在这里谈论数据重播。根据我在加入期间的理解,Kafka将数据插入主题的时间作为JoinWindow的时间,因此如果您想要重放数据并重新插入数据6个月前,kafka将其作为新数据,将其作为新数据今天插入,并加入一些其他实际上今天应该没有的数据。
答案 0 :(得分:4)
Kafka的Streams API使用TimestampExtractor
返回的时间戳来计算联接。默认情况下,这是记录的嵌入式元数据时间戳。 (c.f。http://docs.confluent.io/current/streams/concepts.html#time)
默认情况下,KafkaProducer
将此时间戳设置为写入时的当前系统时间。 (作为替代方案,您可以基于每个主题配置代理,以在代理存储记录时使用代理的系统时间覆盖生产者提供的记录时间戳 - 这提供了“提取时间”语义。)
因此,本身并不是Kafka Streams问题。
有多种方法可以解决这个问题:
如果您的数据已经在主题中,则只需重置Streams应用程序即可重新处理旧数据。为此,您可以使用应用程序重置工具(bin/kafka-streams-application-reset.sh
)。您还需要在Streams应用中将auto.offset.reset
政策指定为earliest
。查看文档 - 同时,建议阅读博客文章。
这是最好的方法,因为您不需要再次向主题写入数据。
KafkaProducer producer = new KafkaProducer(...);
producer.send(new ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value));
因此,如果您摄取旧数据,您可以明确设置时间戳,Kafka Streams会选择它并相应地计算连接。