Google cloud dataflow 从BigQuery读取数据流时使用Dataflow-Nullpointer的Apache Beam

Google cloud dataflow 从BigQuery读取数据流时使用Dataflow-Nullpointer的Apache Beam,google-cloud-dataflow,apache-beam,apache-beam-io,Google Cloud Dataflow,Apache Beam,Apache Beam Io,我正在用ApacheBeam编写的google数据流上运行一个作业,该作业可以读取BigQuery表和文件。转换数据并将其写入其他BigQuery表。作业“通常”成功,但有时我在从大查询表读取时随机获得nullpointer异常,而我的作业失败: (288abb7678892196): java.lang.NullPointerException at org.apache.beam.sdk.io.gcp.bigquery.BigQuerySourceBase.split(BigQuerySou

我正在用ApacheBeam编写的google数据流上运行一个作业,该作业可以读取BigQuery表和文件。转换数据并将其写入其他BigQuery表。作业“通常”成功,但有时我在从大查询表读取时随机获得nullpointer异常,而我的作业失败:

(288abb7678892196): java.lang.NullPointerException
at org.apache.beam.sdk.io.gcp.bigquery.BigQuerySourceBase.split(BigQuerySourceBase.java:98)
at com.google.cloud.dataflow.worker.runners.worker.WorkerCustomSources.splitAndValidate(WorkerCustomSources.java:261)
at com.google.cloud.dataflow.worker.runners.worker.WorkerCustomSources.performSplitTyped(WorkerCustomSources.java:209)
at com.google.cloud.dataflow.worker.runners.worker.WorkerCustomSources.performSplitWithApiLimit(WorkerCustomSources.java:184)
at com.google.cloud.dataflow.worker.runners.worker.WorkerCustomSources.performSplit(WorkerCustomSources.java:161)
at com.google.cloud.dataflow.worker.runners.worker.WorkerCustomSourceOperationExecutor.execute(WorkerCustomSourceOperationExecutor.java:47)
at com.google.cloud.dataflow.worker.runners.worker.DataflowWorker.executeWork(DataflowWorker.java:341)
at com.google.cloud.dataflow.worker.runners.worker.DataflowWorker.doWork(DataflowWorker.java:297)
at com.google.cloud.dataflow.worker.runners.worker.DataflowWorker.getAndPerformWork(DataflowWorker.java:244)
at com.google.cloud.dataflow.worker.runners.worker.DataflowBatchWorkerHarness$WorkerThread.doWork(DataflowBatchWorkerHarness.java:125)
at com.google.cloud.dataflow.worker.runners.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:105)
at com.google.cloud.dataflow.worker.runners.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:92)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
我不知道这和什么有关。当我清除临时目录并重新加载模板时,作业再次通过

我阅读BQ的方式很简单:

BigQueryIO.read().fromQuery()
我将非常感谢任何帮助


有人吗?

好的,让我再详细介绍一下

  • 作业作为模板上传并在google数据流上运行
  • 这项工作通常是成功的——这就是为什么我怀疑实际代码是否有问题。异常来自源代码,它看起来像:
    bqServices.getDatasetService(bqOptions)
    在BigQuerySourceBase中返回null
  • 是的,我确实提供了实际的查询
下面是我的工作。如您所见,此运行已成功。它处理了从BQ导出的200多万行,从csv文件导出的150万行,并将800k写回BigQuery(数字是正确的)。这项工作基本上是按预期进行的。 左上角(读取事务)是对BQ进行查询的步骤。这一步有时会无缘无故地失败

下面是在BQ源上使用Nullpointer失败时的同一作业

我不确定代码片段在这种情况下会有多大帮助,但这是执行查询的一部分:

PCollection<Transaction> transactions = p.apply("Read Transactions", BigQueryIO.read().fromQuery(createTransactionQuery(options)))
                                        .apply("Map to Transaction", MapElements.via(new TableRowToTransactionFn()));

    PCollection<KV<String, Transaction>> transactionsPerMtn = 
            transactions.apply("Filter Transactions Without MTN", Filter.by(t -> t.transactionMtn != null))
                        .apply("Map Transactions to MTN key", MapElements.into(
                    TypeDescriptors.kvs(TypeDescriptors.strings(), TypeDescriptor.of(Transaction.class)))
                                    .via(t -> KV.of(t.transactionMtn, t)));
private ValueProvider<String> createTransactionQuery(TmsPipelineOptions options) {
    return NestedValueProvider.of(options.getInputTransactionTable(), table -> {
        StringBuilder sb = new StringBuilder();
        sb.append(
                "SELECT transaction_id, transaction_mtn, transaction_folio_number, transaction_payer_folio_number FROM ");
        sb.append(table);
        return sb.toString();
    });
}
PCollection transactions=p.apply(“读取事务”,BigQueryIO.Read().fromQuery(createTransactionQuery(选项)))
.apply(“映射到事务”,MapElements.via(new TableRowToTransactionFn()));
PCollection transactionsPerMtn=
transactions.apply(“筛选不带MTN的事务”,筛选依据(t->t.transactionMtn!=null))
.apply(“将事务映射到MTN键”,MapElements.into(
kvs(TypeDescriptors.strings(),TypeDescriptor.of(Transaction.class)))
.通过(t->KV.of(t.transactionMtn,t));
下面是获取查询的方法:

PCollection<Transaction> transactions = p.apply("Read Transactions", BigQueryIO.read().fromQuery(createTransactionQuery(options)))
                                        .apply("Map to Transaction", MapElements.via(new TableRowToTransactionFn()));

    PCollection<KV<String, Transaction>> transactionsPerMtn = 
            transactions.apply("Filter Transactions Without MTN", Filter.by(t -> t.transactionMtn != null))
                        .apply("Map Transactions to MTN key", MapElements.into(
                    TypeDescriptors.kvs(TypeDescriptors.strings(), TypeDescriptor.of(Transaction.class)))
                                    .via(t -> KV.of(t.transactionMtn, t)));
private ValueProvider<String> createTransactionQuery(TmsPipelineOptions options) {
    return NestedValueProvider.of(options.getInputTransactionTable(), table -> {
        StringBuilder sb = new StringBuilder();
        sb.append(
                "SELECT transaction_id, transaction_mtn, transaction_folio_number, transaction_payer_folio_number FROM ");
        sb.append(table);
        return sb.toString();
    });
}
private ValueProvider createTransactionQuery(TmsPipelineOptions选项){
返回NestedValueProvider.of(options.getInputTransactionTable(),table->{
StringBuilder sb=新的StringBuilder();
附加(
“从中选择交易id、交易mtn、交易对账单号、交易付款人对账单号”);
某人附加(表格);
使某人返回字符串();
});
}
我相信在大查询源代码中存在某种缺陷,这会导致类似的问题。我只是无法确定是什么原因造成的,因为这是随机发生的。
就像我写的,上次我遇到它时,我只是清除了gcs上的temp dir并重新上传了我的模板(没有任何代码更改),然后工作又开始了。

我最终在google issuetracker中添加了bug。 在与google员工进行了长时间的交谈和调查后,发现将模板用于从BigQuery读取的数据流批处理作业是没有意义的,因为您只能执行一次

引用:“对于BigQuery批处理管道,模板只能执行一次,因为BigQuery作业ID是在模板创建时设置的。此限制将在SDK 2的未来版本中删除,但我不能说。 创建模板:“

如果错误比NullpointerException更清楚,那还是好的

无论如何,我希望这对将来的人有所帮助

如果有人对整个对话感兴趣,问题就出在这里:

我也遇到了这个问题,在仔细研究之后,发现该限制在2.2.0版中已被删除。然而,它还没有正式发布。您可以在他们的网站上查看此版本的进度(似乎只剩下一个问题)

但是如果您现在想使用它,您可以自己编译它,这并不困难。只需从他们的签出标签
v2.2.0-RC4
中签出源代码,然后运行
mvn clean install
。然后只需在
pom.xml
中修改项目依赖项,以指向版本
2.2.0

从2.2.0开始,如果您想对模板使用
BigQueryIO
,则需要调用
withTemplateCompatibility()


我目前正在为我的项目使用2.2.0,到目前为止效果很好。

您是否正在向源代码中添加实际的查询?或者您只是调用
fromQuery()
而没有任何参数?另外,Read不是一个函数,而是一个内部类。您是直接运行管道还是使用运行程序创建模板然后运行它?为什么不在本地运行并调试它呢!?您是否对从biquery读取的数据执行任何pardo转换?如果是的话,请提供代码片段,你到底在哪里得到空指针异常?啊,很高兴知道!谢谢分享。目前,该代码在prod上运行了几个月,没有模板,但很高兴知道他们最终添加了模板。干杯。这个,救了我的命!:D我从BQ商店中读取,随着新项目的添加,更新了日期范围。对我来说似乎是一个合理的用例…你有没有找到解决方案?据我所知,如果管道使用BigQuery,则不能使用gcloud数据流命令触发管道。根据你从谷歌得到的回复,它是按设计工作的吗?在我的解决方案中,我只是放弃了模板,因为当时它们不受支持。但是如果你阅读下面Hasyimi的回答,你会发现他提到这已经在2.2.0中解决了。他们在BigQueryIO中添加了模板兼容性。哦,我发现了问题所在,