Java 使用ParDo'消费restapi;s进程元素

Java 使用ParDo'消费restapi;s进程元素,java,firebase,google-cloud-dataflow,Java,Firebase,Google Cloud Dataflow,当我将CSV快速上传到Firebase时,我只是这样做,而不是编写自定义接收器。这是对代码的过度简化: public static void main(String[] args) throws Exception { Options options = PipelineOptionsFactory.as(Options.class); Pipeline p = Pipeline.create(options); PCollection<String> C

当我将CSV快速上传到Firebase时,我只是这样做,而不是编写自定义接收器。这是对代码的过度简化:

public static void main(String[] args) throws Exception {

    Options options = PipelineOptionsFactory.as(Options.class);
    Pipeline p = Pipeline.create(options);

    PCollection<String> CsvData = p.apply(TextIO.Read.from("/my_file.csv"));
    CsvData.apply(ParDo.named("Firebase").of(new DoFn<String, Void>() {
          @Override
          public void processElement(ProcessContext c) {
              Firebase fb = new Firebase("https://MYAPP.firebaseio.com/");
              fb.child("someId").setValue(c.element.getValue());
          }
        });

}
publicstaticvoidmain(字符串[]args)引发异常{
Options Options=pipelineoptions工厂.as(Options.class);
Pipeline p=Pipeline.create(选项);
PCollection CsvData=p.apply(TextIO.Read.from(“/my_file.csv”);
CsvData.apply(ParDo.named(“Firebase”)of(new DoFn(){
@凌驾
公共void processElement(ProcessContext c){
Firebase fb=新Firebase(“https://MYAPP.firebaseio.com/");
fb.child(“someId”).setValue(c.element.getValue());
}
});
}

它可以工作。这是不是应该在云数据流上使用REST API?

是的,这应该可以工作,假设您同意以下警告:如果出现故障,可以复制或重试捆绑包多次,也就是说,
processElement
调用可以在同一元素上多次调用,可能是并发调用

即使数据流将重复消除结果(即,通过
c.output()
发出的一个成功调用的项将在结果
PCollection
中结束),重复消除副作用(例如进行外部API调用)也是您的代码的责任

定制的sinkapi仅仅强调了这些问题,并提供了一种处理这些问题的“模式”(通过提供具有唯一ID的捆绑包并提供一个钩子来提交成功的结果,例如,基于文件的接收器将使每个捆绑包写入一个唯一命名的临时文件,提交钩子将成功完成的捆绑包写入的文件重命名为最终位置)-但是如果您的用例对它们不敏感,那么您完全可以使用简单的
ParDo

此外,请注意,数据流还没有用于流的自定义接收器API,因此如果这是一个流管道,那么
ParDo
肯定是正确的选择


在您的ParDo中,您可能希望实现对Firebase调用的批处理,以避免每次调用的开销。您可以使用
DoFn.finishBundle()
(即,在缓冲区中维护批处理更新,在
processElement
中附加到批处理更新,并在批处理过大时刷新,最后一次在
finishBundle
中刷新批处理更新)。请参阅中类似模式的示例。

是的,假设您同意以下警告,则此模式应该可以工作:如果出现故障,捆绑包可能会被复制或重试多次,即您的
processElement
调用可能会在同一元素上被多次调用,可能是并发调用

即使数据流将重复消除结果(即,通过
c.output()
发出的一个成功调用的项将在结果
PCollection
中结束),重复消除副作用(例如进行外部API调用)也是您的代码的责任

定制的sinkapi仅仅强调了这些问题,并提供了一种处理这些问题的“模式”(通过提供具有唯一ID的捆绑包并提供一个钩子来提交成功的结果,例如,基于文件的接收器将使每个捆绑包写入一个唯一命名的临时文件,提交钩子将成功完成的捆绑包写入的文件重命名为最终位置)-但是如果您的用例对它们不敏感,那么您完全可以使用简单的
ParDo

此外,请注意,数据流还没有用于流的自定义接收器API,因此如果这是一个流管道,那么
ParDo
肯定是正确的选择


在您的ParDo中,您可能希望实现对Firebase调用的批处理,以避免每次调用的开销。您可以使用
DoFn.finishBundle()
(即,在缓冲区中维护批处理更新,在
processElement
中附加到批处理更新,并在批处理过大时刷新,最后一次在
finishBundle
中刷新批处理更新)。请参阅中类似模式的示例。

太好了!感谢您的详细解释!我将为流式传输的每个项目保留一个唯一的id,以避免重复,因此在多次调用时,它只会覆盖自身。请注意,如果使用窗口,则在DoFn的私有状态下维护缓冲区将跨窗口混合数据,因此无论您在finishBundle()中执行什么操作,都会在windows上任意操作(windows可能分布在DoFn实例上)。太好了!感谢您的详细解释!我将为流式传输的每个项目保留一个唯一的id,以避免重复,因此它在多次调用时只会覆盖自身。请注意,如果您使用窗口,则在DoFn的私有状态下维护缓冲区将跨窗口混合数据,因此无论您在finishBundle()中执行什么操作将相当随意地跨窗口运行(窗口可能分布在DoFn实例中)。