Google cloud dataflow 有状态ParDo不在数据流运行程序上工作

Google cloud dataflow 有状态ParDo不在数据流运行程序上工作,google-cloud-dataflow,dataflow,apache-beam,Google Cloud Dataflow,Dataflow,Apache Beam,基于Javadocs和上的博客文章,我尝试使用一个简单的重复数据消除示例,使用2.0.0-beta-2SDK从GCS读取一个文件(包含一个JSON列表,每个JSON都有一个用户id字段),然后通过管道运行,如下所述 输入数据包含约146K个事件,其中只有50个事件是唯一的。整个输入大约为50MB,与2分钟的固定窗口相比,可以在相当短的时间内处理。我只是在那里放置了一个窗口,以确保在不使用GlobalWindow的情况下保持每键每窗口语义。我通过3个并行阶段运行窗口化数据,以比较结果,下面将对每个

基于Javadocs和上的博客文章,我尝试使用一个简单的重复数据消除示例,使用2.0.0-beta-2SDK从GCS读取一个文件(包含一个JSON列表,每个JSON都有一个用户id字段),然后通过管道运行,如下所述

输入数据包含约146K个事件,其中只有50个事件是唯一的。整个输入大约为50MB,与2分钟的固定窗口相比,可以在相当短的时间内处理。我只是在那里放置了一个窗口,以确保在不使用GlobalWindow的情况下保持每键每窗口语义。我通过3个并行阶段运行窗口化数据,以比较结果,下面将对每个阶段进行解释

  • 只需将内容复制到GCS上的一个新文件中-这确保了所有事件都按预期进行处理,并且我验证了内容与输入完全相同
  • 在用户id上Combine.PerKey,并仅从Iterable中选取第一个元素-这基本上应该消除数据重复,并按预期工作。生成的文件具有原始事件列表中唯一项的确切数量-50个元素
  • 有状态ParDo,检查密钥是否已被看到,并且仅当其未被看到时才发出输出。理想情况下,这样做的结果应该与重复数据匹配[2],但我看到的只是3个唯一的事件。这3个独特的事件总是指向我在几次运行中使用的3个相同的用户ID 有趣的是,当我从DataflowRunner切换到在本地运行整个流程的DirectRunner时,我发现[3]的输出与[2]匹配,正如预期的那样,只有50个唯一的元素。因此,我怀疑有状态ParDo的DataflowRunner是否存在任何问题

    公共类StatefulParDoSample{
    私有静态记录器Logger=LoggerFactory.getLogger(StatefulParDoSample.class.getName());
    静态类StatefulDoFn扩展了DoFn{
    final Aggregator processedElements=createAggregator(“processed”,Sum.ofLongs());
    final Aggregator skippedElements=createAggregator(“skipped”,Sum.ofLongs());
    @StateId(“keyTracker”)
    私有最终状态规范keyTrackerSpec=
    StateSpecs.value(VarIntCoder.of());
    @过程元素
    公共无效处理元素(
    ProcessContext上下文,
    @StateId(“keyTracker”)值State keyTracker){
    已处理元素。添加值(1l);
    最后一个字符串userId=context.element().getKey();
    int wasSeen=firstNonNull(keyTracker.read(),0);
    如果(wasSeen==0){
    keyTracker.write(1);
    context.output(context.element().getValue());
    }否则{
    keyTracker.write(wasSeen+1);
    跳过元素。添加值(1l);
    }
    }
    }
    公共静态void main(字符串[]args){
    DataflowPipelineOptions pipelineOptions=pipelineOptions工厂.create().as(DataflowPipelineOptions.class);
    setRunner(DataflowRunner.class);
    pipelineOptions.setProject(“项目名称”);
    管道选项。设置标记位置(GCS\U标记位置);
    pipelineOptions.setStreaming(假);
    pipelineOptions.setAppName(“重复数据消除程序”);
    Pipeline p=Pipeline.create(pipelineOptions);
    最终ObjectMapper映射器=新ObjectMapper();
    PCollection键事件=
    P
    .apply(TextIO.Read.from(GCS_样本_输入_文件_路径))
    .apply(带键)of(新的SerializableFunction(){
    @凌驾
    公共字符串应用(字符串输入){
    试一试{
    映射事件JSON=
    readValue(输入,Map.class);
    return(String)eventJson.get(“user_id”);
    }捕获(例外e){
    }
    返回“”;
    }
    }))
    .申请(
    开窗(
    固定窗口(持续时间标准分钟(2))
    )
    );
    关键事件
    .apply(ParDo.of(new StatefulDoFn()))
    .apply(TextIO.Write.to(GCS_样本_输出_文件_路径).withNumShards(1));
    关键事件
    .apply(value.create())
    .apply(TextIO.Write.to(GCS_SAMPLE_COPY_FILE_PATH).withNumShards(1));
    关键事件
    .apply(Combine.perKey(新的SerializableFunction()){
    @凌驾
    公共字符串应用(Iterable输入){
    return!input.iterator().hasNext()?“empty”:input.iterator().next();
    }
    }))
    .apply(value.create())
    .apply(TextIO.Write.to(GCS_SAMPLE_COMBINE_FILE_PATH).withNumShards(1));
    PipelineResult=p.run();
    result.waitUntilFinish();
    }
    }
    
    这是批处理模式下数据流服务中的一个错误,在即将发布的0.6.0 Beam版本中修复(如果您跟踪前沿,则修复为HEAD)


    谢谢你引起我的注意!作为参考,或者如果出现任何其他问题,这是由跟踪的。

    这是批处理模式下数据流服务中的一个错误,在即将发布的0.6.0 Beam版本中修复(如果跟踪前沿,则为HEAD)


    谢谢你引起我的注意!作为参考,或者如果出现任何其他问题,我将对此进行跟踪。

    我将查看一下。我已经更新了我的答案-这在HEAD和0.6.0版本中以批处理模式工作。我将查看一下。我已经更新了我的答案-这在HEAD和0.6.0版本中以批处理模式工作。因此,你是说这可以在流模式下正常工作吗?我这样问是因为我最终会在流模式下运行管道-因此,这可能不是一个拦截器,如果是这样的话。是的,它应该在流模式下工作。我专门在流模式下运行了您的示例代码作为测试,并获得了成功。谢谢