Java 每X封来自Pubsub的消息写入云存储
我对CloudDataflow/ApacheBeam还不熟悉,所以这个概念/编程对我来说仍然很模糊 我想做的是,Dataflow侦听Pubsub并获取JSON格式的消息:Java 每X封来自Pubsub的消息写入云存储,java,google-cloud-dataflow,apache-beam,google-cloud-pubsub,Java,Google Cloud Dataflow,Apache Beam,Google Cloud Pubsub,我对CloudDataflow/ApacheBeam还不熟悉,所以这个概念/编程对我来说仍然很模糊 我想做的是,Dataflow侦听Pubsub并获取JSON格式的消息: { "productId": "...", "productName": "..." } 并将其转化为: { "productId": "...", "productName": "...", "sku": "...", "inventory": { "revenue": <some D
{
"productId": "...",
"productName": "..."
}
并将其转化为:
{
"productId": "...",
"productName": "...",
"sku": "...",
"inventory": {
"revenue": <some Double>,
"stocks": <some Integer>
}
}
请填写缺少的部分,并告诉我有关窗口设置的提示(例如,什么是适当的配置等),以及我应该在哪些步骤中插入/应用它。- 我认为您不需要在
和IngestFromPubsub
中使用任何窗口。窗口化的目的是将时间上相邻的记录分组到窗口中,以便可以对它们进行聚合计算。但是,由于您不进行任何聚合计算,并且对独立处理每条记录感兴趣,因此不需要windowsEnricDataFromAPI
- 由于您总是将一个输入记录转换为一个输出记录,因此
应该是一个。这将使代码更容易编写EnricDataFromAPI
- 在ApacheBean Java中处理JSON有很多资源:
- 您不必使用Jackson将JSON映射到Java对象。您可以直接操作JSON。您可以使用Java来解析/操作/序列化
- 我认为您不需要在
和IngestFromPubsub
中使用任何窗口。窗口化的目的是将时间上相邻的记录分组到窗口中,以便可以对它们进行聚合计算。但是,由于您不进行任何聚合计算,并且对独立处理每条记录感兴趣,因此不需要windowsEnricDataFromAPI
- 由于您总是将一个输入记录转换为一个输出记录,因此
应该是一个。这将使代码更容易编写EnricDataFromAPI
- 在ApacheBean Java中处理JSON有很多资源:
- 您不必使用Jackson将JSON映射到Java对象。您可以直接操作JSON。您可以使用Java来解析/操作/序列化
sku
值?它是否保留在源消息中,从Pub/Sub传递?就像从myapihost.com/api/products/获取一样简单。是的,sku
会保留在原始消息中。在写入GCS时,您希望执行自定义批处理的原因是什么?Beam默认为您执行批处理。@MikhailGryzykhin最初,我只希望一条记录一次存储写入。最初我没有窗口设置,但当我尝试执行时,出现了一个运行时错误,说我需要窗口设置,因为option.setStreaming(true)
。这很有意义,可能是因为它是一条无界流,Beam希望根据时间将记录组合在一起。我的问题更倾向于可能性。你如何获得sku
价值?它是否保留在源消息中,从Pub/Sub传递?就像从myapihost.com/api/products/获取一样简单。是的,sku
会保留在原始消息中。在写入GCS时,您希望执行自定义批处理的原因是什么?Beam默认为您执行批处理。@MikhailGryzykhin最初,我只希望一条记录一次存储写入。最初我没有窗口设置,但当我尝试执行时,出现了一个运行时错误,说我需要窗口设置,因为option.setStreaming(true)
。这很有意义,可能是因为它是一条无界流,Beam希望根据时间将记录组合在一起。我的问题更多的是关于可能性的。这是我最初做的,没有窗口。但是,当我执行此操作时,出现一个运行时错误,该错误表示我需要打开窗口,因为option.setStreaming(true)
。我现在不想为窗口设置而烦恼,因为我已经开始了解这一点了。您能将所有窗口设置移到EnricDataFromAPI
和WriteToGCS
步骤之间吗?你还会有运行时错误吗?这是我删除窗口时得到的结果java.lang.IllegalArgumentException:在将writefile应用于无界PCollection时必须使用窗口写入
我需要更多信息。哪一行抛出异常?异常是由EnricDataFromAPI
、WriteToGCS
或IngestFromPubsub
引起的吗?您可以通过尝试或错误来确定这一点(从管道中删除一个步骤,重试,检查异常,将其放回,然后重复)。如果使用WindowedWrites删除,会发生什么情况?
您是否尝试将MapElements
用于EnricDataFromAPI
?您是否尝试过在EnricDataFromAPI
和WriteToGCS
之间添加窗口化步骤?我最初就是这么做的,没有窗口化。但是,当我执行此操作时,出现一个运行时错误,该错误表示我需要打开窗口,因为option.setStreaming(true)
。我现在不想为窗口设置而烦恼,因为我已经开始了解这一点了。您能将所有窗口设置移到EnricDataFromAPI
和WriteToGCS
步骤之间吗?你还会有运行时错误吗?这是我删除窗口时得到的结果java.lang.IllegalArgumentException:在将writefile应用于无界PCollection时必须使用窗口写入
我需要更多信息。哪一行抛出异常?异常是由EnricDataFromAPI
、WriteToGCS
或IngestFromPubsub
引起的吗?您可以通过尝试或错误来确定这一点(从管道中删除一个步骤,重试,检查异常,将其放回,然后重复)。如果使用WindowedWrites删除,会发生什么情况?
您是否尝试将MapElements
用于EnricDataFromAPI
?您是否尝试过在EnricDataFromAPI
和WriteToGCS
之间添加窗口步骤?
public static void main(String[] args) {
Options options = PipelineOptionsFactory.fromArgs(args).withValidation().as(Options.class);
options.setStreaming(true);
Pipeline pipeline = Pipeline.create(options);
pipeline
.apply("IngestFromPubsub", PubsubIO.readStrings().fromTopic(options.getTopic()))
// I don't really understand the next part, I just copied from official documentation and filled in some values
.apply(Window.<String>into(FixedWindows.of(Duration.millis(5000)))
.withAllowedLateness(Duration.millis(5000))
.triggering(AfterProcessingTime.pastFirstElementInPane().plusDelayOf(Duration.millis(1000)))
.discardingFiredPanes()
)
.apply("EnrichDataFromAPI", ParDo.of(
new DoFn<String, String>() {
@ProcessElement
public void processElement(ProcessContext c) {
c.element();
// help on this part, I heard I need to use Jackson but I don't know, for API HttpClient is sufficient
// ... deserialize, call API, serialize again ...
c.output(enrichedJSONString);
}
}
))
.apply("WriteToGCS",
TextIO.write().withWindowedWrites().withNumShards(1).to(options.getOutput()))
;
PipelineResult result = pipeline.run();
}