问题声明为,我们正在自定义Google提供的PubSubToBQ Dataflow流Java模板,在该模板中,我们配置多个预订/主题以读取并将其推入多个Bigquery表中,这需要作为单个执行数据流管道以从源读取所有流并将其推入Bigquery表。但是,当我们从eclipse执行模板时,我们必须传递Subscription / Topic和BQ详细信息,并在gcs存储桶上传递tempalte阶段,然后当我们使用带有不同Subscription和BQ详细信息的gcloud命令运行模板时。数据流作业不会被新的Subscription或BQ表覆盖。
目标:我的目标是使用Google提供的PubSubTOBQ.java类模板,并传递带有相应Bigquery表的订阅列表,并为每个表创建传递订阅的管道。因此,单个作业中的n-n,n个管道。
我正在使用Google提供的PubSubTOBQ.java类模板,该模板将输入作为单个订阅或单个主题以及相应的Big Query Table详细信息。
现在,我需要对其进行自定义,以将输入作为主题列表或订阅列表以逗号分隔。我能够使用ValueProvider>并在main或run方法内部进行访问,我通过String数组进行迭代,并将subscription / topic和bq表作为字符串传递。查看下面的代码以获取更多信息。
我在gcp doc上看到的是,如果我们想在朗姆会议期间覆盖或使用值来创建动态Piepline,则无法在DoFn之外传递ValueProvider变量。不知道我们是否可以阅读DoFn中的消息。
**PubsubIO.readMessagesWithAttributes().fromSubscription(providedSubscriptionArray[i])**
如果是,请告诉我。这样我的目标就实现了。
代码:
public static void main(String[] args) {
StreamingDataflowOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
.as(StreamingDataflowOptions.class);
List<String> listOfSubStr = new ArrayList<String>();
List<String> listOfTopicStr = new ArrayList<String>();
List<String> listOfTableStr = new ArrayList<String>();
String[] providedSubscriptionArray = null;
String[] providedTopicArray = null;
String[] providedTableArray = null;
if (options.getInputSubscription().isAccessible()) {
listOfSubStr = options.getInputSubscription().get();
providedSubscriptionArray = new String[listOfSubStr.size()];
providedSubscriptionArray = createListOfProvidedStringArray(listOfSubStr);
}
if (options.getInputTopic().isAccessible()) {
listOfTopicStr = options.getInputTopic().get();
providedTopicArray = new String[listOfSubStr.size()];
providedTopicArray = createListOfProvidedStringArray(listOfTopicStr);
}
if (options.getOutputTableSpec().isAccessible()) {
listOfTableStr = options.getOutputTableSpec().get();
providedTableArray = new String[listOfSubStr.size()];
providedTableArray = createListOfProvidedStringArray(listOfTableStr);
}
Pipeline pipeline = Pipeline.create(options);
PCollection<PubsubMessage> readPubSubMessage = null;
for (int i = 0; i < providedSubscriptionArray.length; i++) {
if (options.getUseSubscription()) {
readPubSubMessage = pipeline
.apply(PubsubIO.readMessagesWithAttributes().fromSubscription(providedSubscriptionArray[i]));
} else {
readPubSubMessage = pipeline.apply(PubsubIO.readMessagesWithAttributes().fromTopic(providedTopicArray[i]));
}
readPubSubMessage
/*
* Step #2: Transform the PubsubMessages into TableRows
*/
.apply("Convert Message To TableRow", ParDo.of(new PubsubMessageToTableRow()))
.apply("Insert Data To BigQuery",
BigQueryIO.writeTableRows().to(providedTableArray[i])
.withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_NEVER)
.withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_APPEND));
}
pipeline.run().waitUntilFinish();
}
应该能够将单个Dataflow PubSubTOBQ模板用于与单个Dataflow Streaming Job中的bigquery模板数量相对应的多个订阅数量管道。
答案 0 :(得分:0)
问题在于,到目前为止,Dataflow模板需要在登台/创建时知道管道图,以便它在运行时不会有所不同。如果您仍想使用非模板化管道并通过逗号分隔的发布/订阅主题列表作为--topicList
选项参数来进行操作,则可以执行以下操作:
String[] listOfTopicStr = options.getTopicList().split(",");
PCollection[] p = new PCollection[listOfTopicStr.length];
for (int i = 0; i < listOfTopicStr.length; i++) {
p[i] = pipeline
.apply(PubsubIO.readStrings().fromTopic(listOfTopicStr[i]))
.apply(ParDo.of(new DoFn<String, Void>() {
@ProcessElement
public void processElement(ProcessContext c) throws Exception {
Log.info(String.format("Message=%s", c.element()));
}
}));
}
完整代码here。
如果我们用3个主题进行测试,例如:
mvn -Pdataflow-runner compile -e exec:java \
-Dexec.mainClass=com.dataflow.samples.MultipleTopics \
-Dexec.args="--project=$PROJECT \
--topicList=projects/$PROJECT/topics/topic1,projects/$PROJECT/topics/topic2,projects/$PROJECT/topics/topic3 \
--stagingLocation=gs://$BUCKET/staging/ \
--runner=DataflowRunner"
gcloud pubsub topics publish topic1 --message="message 1"
gcloud pubsub topics publish topic2 --message="message 2"
gcloud pubsub topics publish topic3 --message="message 3"
输出和数据流图将符合预期:
将这种方法强加到模板中的可能解决方法是在最坏的情况下拥有足够多的主题N
。当我们以n
个主题(令人满意的n <= N
)执行模板时,我们需要指定N - n
个未使用/虚拟的主题来填充。