Google cloud dataflow Beam.io.WriteToPubSub抛出错误“;给定的pcollpone[WriteToPubSub/Write/NativeWrite.None]不是dict、iterable或PCollection";

Google cloud dataflow Beam.io.WriteToPubSub抛出错误“;给定的pcollpone[WriteToPubSub/Write/NativeWrite.None]不是dict、iterable或PCollection";,google-cloud-dataflow,apache-beam,google-cloud-pubsub,Google Cloud Dataflow,Apache Beam,Google Cloud Pubsub,每当我使用“WriteToPubSub”时,就会出现一个错误。下面的代码是我试图调试该问题的代码。我的实际代码试图从WriteToBigQuery的失败中获取数据,以便将其推送到死信发布子主题。但当我尝试这样做时,我不断遇到下面的错误。 我正在运行ApacheBeam2.27和Python3.8 import apache_beam as beam from apache_beam.runners.interactive.interactive_runner import Interactive

每当我使用“WriteToPubSub”时,就会出现一个错误。下面的代码是我试图调试该问题的代码。我的实际代码试图从WriteToBigQuery的失败中获取数据,以便将其推送到死信发布子主题。但当我尝试这样做时,我不断遇到下面的错误。 我正在运行ApacheBeam2.27和Python3.8

import apache_beam as beam
from apache_beam.runners.interactive.interactive_runner import InteractiveRunner
from apache_beam.io.gcp.bigtableio import WriteToBigTable
from apache_beam.runners import DataflowRunner
import apache_beam.runners.interactive.interactive_beam as ib
from apache_beam.options import pipeline_options
from apache_beam.options.pipeline_options import GoogleCloudOptions
import google.auth
import json
import pytz


# Setting up the Apache Beam pipeline options.
options = pipeline_options.PipelineOptions(flags=[])

# Sets the project to the default project in your current Google Cloud environment.
_, options.view_as(GoogleCloudOptions).project = google.auth.default()

# Sets the Google Cloud Region in which Cloud Dataflow runs.
options.view_as(GoogleCloudOptions).region = 'asia-east1'

# Sets the job name
options.view_as(GoogleCloudOptions).job_name = 'data_ingest'

# IMPORTANT! Adjust the following to choose a Cloud Storage location.
dataflow_gcs_location = '[REDACTED]'

# Dataflow Staging Location. This location is used to stage the Dataflow Pipeline and SDK binary.
options.view_as(GoogleCloudOptions).staging_location = '%s/staging' % dataflow_gcs_location

# Dataflow Temp Location. This location is used to store temporary files or intermediate results before finally outputting to the sink.
options.view_as(GoogleCloudOptions).temp_location = '%s/temp' % dataflow_gcs_location

# The directory to store the output files of the job.
output_gcs_location = '%s/output' % dataflow_gcs_location

ib.options.recording_duration = '1m'

# The Google Cloud PubSub topic for this example.
topic = "[REDACTED]"
output_topic = "[REDACTED]"
subscription = "[REDACTED]"
deadletter_topic = "[REDACTED]"


class PrintValue(beam.DoFn):
    def process(self, element):
        print(element)
        return [element]

p = beam.Pipeline(InteractiveRunner(),options=options)
data = p | beam.io.ReadFromPubSub(topic=topic) | beam.ParDo(PrintValue()) | beam.io.WriteToPubSub(topic=deadletter_topic)

ib.show(data, include_window_info=False)
给出的错误是

ValueError: The given pcoll PDone[WriteToPubSub/Write/NativeWrite.None] is not a dict, an iterable or a PCollection.
有人能发现问题所在吗? 不管我做什么,WriteToPubSub都说它收到了PDone

编辑: 如果使用p.run(),则会出现以下错误:

'PDone' object has no attribute 'to_runner_api'
在这两种情况下,管道都不会尝试运行,它会立即出错

编辑: 我已经意识到了问题所在

p = beam.Pipeline(InteractiveRunner(),options=options)
就是这条线。如果我删除了Interactiver,则一切正常。不知道为什么

光束术语 ApacheBeam有一些基本概念,我们在利用这个编程模型的能力时应该遵循这些概念

管道

简单地说,管道是一系列针对所需输出的任务。它可以像线性流一样简单,也可以有复杂的任务分支。基本概念是从输入源读取,执行一些转换并发射到输出

从数学上讲,beam管道只是一个有向无环的任务图

p收集

简单地说,PCollections是一个不可变的元素包,可以跨机器分发。束流管道中的每一步都将其输入和输出作为PCollection(除源和汇外)

PCollection是一种强大的分布式数据结构,beam pipeline在其上运行。根据您的源类型,它可以是有界的,也可以是无界的

p转换

简单地说,转换是您的pipleine的操作。它提供处理逻辑,该逻辑应用于一个或多个PCollection输入的每个元素

示例:
p转换将X转换为Y。

基于处理范式,beam为我们提供了多个核心转换——ParDo、GroupByKey、Flatte、Combine等

I/O转换

创建管道时,需要数据源来读取文件或数据库等数据。同样,您希望将结果数据发送到外部存储系统,例如主题存储或对象存储。处理外部输入和输出的转换是I/O转换

通常,对于外部源,您将有以下内容

  • 来源:从外部系统读取数据的p转换。这将从 外部系统(如文件、数据库)。它不包含PBegin(管道入口点)并返回PCollection

    转移

    这将是您管道的入口点之一。

  • 接收器:将数据输出到外部系统的数据传输。这将写入外部系统(如主题、存储)。它不包含PCollection并返回一个PDone(管道入口点)

    转移

    这将是管道的出口点之一。

源和汇的组合是一个I/O连接器,如RedisIO、PubSubIO等。Beam提供多个内置连接器,用户也可以编写自定义连接器

上面还有各种概念和扩展,允许用户编写可以在不同运行程序上运行的复杂需求。这就是光束如此强大的原因

解决方案 在您的情况下,ib.show(数据,include_window_info=False)抛出以下错误

ValueError: The given pcoll PDone[WriteToPubSub/Write/NativeWrite.None] is not a dict, an iterable or a PCollection.

因为您的数据包含beam.io.WriteToPubSub(topic=deadletter_topic)的结果,它是一个接收器,返回一个PDone而不是PCollection

对于BQ向PubSub写入失败的用例,您可以遵循以下内容

     data = beam.io.ReadFromPubSub(topic=topic) | 'Write to BQ' >> beam.io.WriteToBigQuery( ...)
        
    (data['beam.io.gcp.bigquery.BigQueryWriteFn.FAILED_ROWS'] 
              | 'publish failed' >> beam.io.WriteToPubSub(topic=deadletter_topic)
但是,如果这不能解决您的问题,那么发布代码将非常有用,或者您可以编写一个带有输出标记的自定义pttransform,用于写入BQ,并返回发布到PubSub的失败(通过元组标记)


注意:不是一个接收器,而是一个自定义的pttransform,它写入大查询并返回失败。

感谢您对这个主题的精彩解释。写得太好了。虽然我已经尝试过你的解决方案,但我仍然会出错。你能根据我在上面的问题中写的简单案例工作并告诉我我做错了什么吗?我已经意识到问题p=beam.Pipeline(InteractiveRunner(),options=options)就是这一行。如果我删除了Interactiver,则一切正常。不确定上面的代码是否正确,接收器无法返回值。我建议您在基础学习之外不要使用interactive runner。它是一个实验模块,应使用DirectRunner进行开发。如果我们想调试InteractiveRunner,请发布这个简单案例的更新代码并完成错误跟踪。对于direct和dataflow runner,您可以参考