Java 如何重新处理成批Kafka流 我想根据消息的时间戳对消息进行批处理 创造 此外,我想在固定时间内批处理这些消息 窗口(1分钟) 只有在窗口通过后,批处理 应该被推到下游

Java 如何重新处理成批Kafka流 我想根据消息的时间戳对消息进行批处理 创造 此外,我想在固定时间内批处理这些消息 窗口(1分钟) 只有在窗口通过后,批处理 应该被推到下游,java,apache-kafka,apache-kafka-streams,Java,Apache Kafka,Apache Kafka Streams,为了实现这一点,处理器API似乎或多或少是合适的(a la): 公共作废流程(字符串键、传感器数据){ //epochTime四舍五入到我们首选的时间窗口(1分钟) 长epochTime=Sensordata.epochTime; ArrayList data=messageStore.get(epochTime); 如果(数据==null){ 数据=新的ArrayList(); } 数据。添加(传感器数据); messageStore.put(id,data); this.context.co

为了实现这一点,处理器API似乎或多或少是合适的(a la):

公共作废流程(字符串键、传感器数据){
//epochTime四舍五入到我们首选的时间窗口(1分钟)
长epochTime=Sensordata.epochTime;
ArrayList data=messageStore.get(epochTime);
如果(数据==null){
数据=新的ArrayList();
}
数据。添加(传感器数据);
messageStore.put(id,data);
this.context.commit();
}
@凌驾
公共void init(ProcessorContext上下文){
this.context=上下文;
this.context.schedule(60000);//等于1分钟
}
@凌驾
公共空标点符号(长时间){
KeyValueIterator it=messageStore.all();
while(it.hasNext()){
KeyValue entry=it.next();
this.context.forward(entry.key,entry.value);
}
//重置消息存储
}
然而,这种方法有一个主要缺点:我们不使用Kafka Streams windows

  • 不考虑顺序错误的消息
  • 实时操作时,标点计划应等于所需的批处理时间窗口。如果我们将其设置为short,批处理将被转发,下游计算将开始快速进行。如果设置为long,并且在批处理窗口尚未完成时触发标点符号,则会出现相同的问题
  • 此外,在保留标点计划(1分钟)的同时重放历史数据将仅在1分钟后触发第一次计算。如果是这样,那将炸毁statestore,也会让人感觉不对
考虑到这些因素,我应该使用Kafka Streams窗口。但这只在卡夫卡流DSL中可能


关于这一点的任何想法都将非常棒。

您可以在DSL中使用
process()
transform()
、或
transformValues()
混合搭配DSL和处理器API(关于这一点,已经有一些其他问题了,所以我不作进一步阐述)。因此,您可以将常规窗口构造与自定义(下游)操作符结合使用,以保留结果(并消除重复数据)。某些重复数据将在窗口操作符中自动发生(从Kafka
0.10.1开始;请参阅),但如果您希望只得到一个结果,缓存将不会为您执行此操作

关于标点符号:它是基于进度(即流时间)触发的,而不是基于挂钟时间——所以如果你重新处理旧的数据,如果你在原始的运行中被称为完全相同的次数(如果你更快地处理旧的数据,那么考虑到时钟时间,那么就更快地在彼此之后)。如果你想了解更多细节,也有一些问题


然而,我要考虑的是:为什么你只需要一个结果?如果您进行流处理,您可能希望构建下游消费者应用程序,以便能够处理结果的更新。这是卡夫卡固有的设计:使用变更日志。

我正在研究:在windows中使用DSL,并在批处理尚未满时让底层计算消费者退出
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
}