尝试运行GCP Cloud-Dataflow管道时遇到问题。
当使用“ DirectRunner”在本地运行时,管道可以工作,但是当尝试使用“ DataflowRunner”在数据流中运行时,管道将失败。
在管道上调用run()
并出现上述错误消息时,它立即立即失败(相对于首先部署到GCP,然后在实际运行管道时失败)。
在对beam.io.WriteToBigQuery
的调用中引发了异常:
(bq_rows
| 'map_to_row' >> beam.Map(to_pred_row)
| 'write_to_table' >> beam.io.WriteToBigQuery(
'my_dataset_name.my_table_name',
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND,
create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED))
如果我用仅写入文件的内容替换管道中的最后一个节点:
(bq_rows
| 'map_to_row' >> beam.Map(to_pred_row)
| 'debug_write_to_csv_2' >> beam.io.WriteToText(additional_opts.out_path, ".txt"))
然后一切都按预期工作,我得到了一个文本文件,其中包含我期望的所有记录。
如果我使用WriteToBigQuery()
函数按原样运行所有内容,但又改回DirectRunner
(并进行其他任何更改),则一切正常,新行将写入BQ表。
据我所知,流入的记录没有什么特别的
WriteToBigQuery
节点。我已经将它们输出到本地和云中运行的文本文件中,以找出导致此错误的原因,但是两个输出看起来都是相同的(并且与目标表的模式匹配)。无论如何,运行流时事情似乎还远远不够以至于出现了意外的值或参数-正如我提到的有关此错误的内容每当我在管道上调用run()
我要去哪里错了?
更新:
这是相同行为的最小示例。创建了一个名为temp_e.words
的表时,该表具有一个名为word
的单(STRING,REQUIRED)列,我可以使用以下代码来重现该行为:
import apache_beam as beam
from google.cloud import storage as gcs
import shutil
from google.cloud import bigquery as bq
import datetime
import os
import json
import apache_beam as beam
from apache_beam.options.pipeline_options import (GoogleCloudOptions,
StandardOptions)
def to_row(word):
return {
'word': word
}
def run_pipeline(local_mode):
PROJECT = 'searchlab-data-insights'
REGION = 'us-central1'
GCS_BUCKET_PATH = 'gs://temp-staging-e'
timestamp = datetime.datetime.now().strftime('%y%m%d-%H%M%S')
options = beam.pipeline.PipelineOptions([
'--project', PROJECT
])
if local_mode:
RUNNER = 'DirectRunner'
else:
RUNNER = 'DataflowRunner'
google_cloud_options = options.view_as(GoogleCloudOptions)
google_cloud_options.project = PROJECT
google_cloud_options.job_name = 'test-{}'.format(timestamp)
google_cloud_options.staging_location = os.path.join(GCS_BUCKET_PATH, 'staging')
google_cloud_options.temp_location = os.path.join(GCS_BUCKET_PATH, 'tmp')
options.view_as(StandardOptions).runner = RUNNER
p = beam.Pipeline(RUNNER, options=options)
bq_rows = p | beam.Create(['words', 'to', 'store'])
(bq_rows
| 'map_to_row' >> beam.Map(to_row)
| 'write_to_table' >> beam.io.WriteToBigQuery(
'temp_e.words',
write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND,
create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED)
)
job = p.run()
if local_mode:
job.wait_until_finish()
print "Done!"
现在运行run_pipeline(local_mode=True)
会产生正确的结果,并附加行,而运行run_pipeline(local_mode=False)
会立即触发错误。
生成的完整错误在这里:https://pastebin.com/xx8wwtXV
答案 0 :(得分:1)
仅当未提供对beam.io.WriteToBigQuery
的调用的架构时,才会出现此问题。看来DirectRunner可以使用现有的表架构工作,但DataflowRunner不能。
在没有更好答案的情况下,我们可以通过显式提供模式来解决它。
因此,例如,在上面的最小示例中,我们可以使用以下代码:
(bq_rows | 'map_to__row' >> beam.Map(to_row) | 'write_to_table' >> beam.io.WriteToBigQuery( 'temp_e.words', schema={"fields":[{"type":"STRING","name":"word","mode":"REQUIRED"}]} write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND, create_disposition=beam.io.BigQueryDisposition.CREATE_IF_NEEDED) )