为了实现这一点,处理器API似乎或多或少适合(la KStream batch process windows):
public void process(String key, SensorData sensorData) {
//epochTime is rounded to our prefered time window (1 minute)
long epochTime = Sensordata.epochTime;
ArrayList<SensorData> data = messageStore.get(epochTime);
if (data == null) {
data = new ArrayList<SensorData>();
}
data.add(sensorData);
messageStore.put(id, data);
this.context.commit();
}
@Override
public void init(ProcessorContext context) {
this.context = context;
this.context.schedule(60000); // equal to 1 minute
}
@Override
public void punctuate(long streamTime) {
KeyValueIterator<String, ArrayList<SensorData>> it = messageStore.all();
while (it.hasNext()) {
KeyValue<String, ArrayList<SensorData>> entry = it.next();
this.context.forward(entry.key, entry.value);
}
//reset messageStore
}
然而,这种方法有一个主要缺点:我们不使用Kafka Streams窗口。
考虑到这些要点,我应该使用Kafka Streams窗口。但这只能在Kafka Streams DSL中实现......
任何对此的强硬都会很棒。
答案 0 :(得分:2)
您可以使用DSL中的process()
,transform()
或transformValues()
混合搭配DSL和处理器API(还有其他一些有关此问题的问题,所以我不详细说明进一步)。因此,您可以将常规窗口构造与自定义(下游)运算符结合使用,以保留结果(并进行重复数据删除)。一些重复数据删除已经在你的窗口操作符中自动发生(从Kafka 0.10.1
开始;请参阅http://docs.confluent.io/current/streams/developer-guide.html#memory-management)但如果你想要只有一个结果,那么缓存将不会为你做。
关于标点符号:它是根据进度(即流时间)触发的,而不是基于挂钟时间 - 因此,如果您重新处理旧数据,将调用与原始数据完全相同的次数运行(如果你考虑挂钟时间,因为你更快地处理旧数据),彼此之后会更快。如果你想获得更多细节,还有一些关于这个的问题。
但是,我一般考虑:为什么你只需要一个结果?如果进行流处理,您可能希望构建下游使用者应用程序,以便能够处理结果的更新。这是Kafka的固有设计:使用changelogs。