如何解决类apache_beam.internal.clients.dataflow.dataflow_v1b3_messages.TypeValueValuesEnum上的Pickling Error?

时间:2016-10-26 11:25:30

标签: google-cloud-dataflow gcloud apache-beam

当我远程运行数据管道时引发了PicklingError:数据管道是使用Beam SDK for Python编写的,我在Google Cloud Dataflow上运行它。当我在本地运行它时,管道工作正常。

以下代码生成PicklingError:这应该重现问题

import apache_beam as beam
from apache_beam.transforms import pvalue
from apache_beam.io.fileio import _CompressionType
from apache_beam.utils.options import PipelineOptions
from apache_beam.utils.options import GoogleCloudOptions
from apache_beam.utils.options import SetupOptions
from apache_beam.utils.options import StandardOptions

if __name__ == "__main__":
  pipeline_options = PipelineOptions()
  pipeline_options.view_as(StandardOptions).runner = 'BlockingDataflowPipelineRunner'
  pipeline_options.view_as(SetupOptions).save_main_session = True
  google_cloud_options = pipeline_options.view_as(GoogleCloudOptions)
  google_cloud_options.project = "project-name"
  google_cloud_options.job_name = "job-name"
  google_cloud_options.staging_location = 'gs://path/to/bucket/staging'
  google_cloud_options.temp_location = 'gs://path/to/bucket/temp'
  p = beam.Pipeline(options=pipeline_options)
  p.run()

以下是Traceback开头和结尾的示例:

WARNING: Could not acquire lock C:\Users\ghousains\AppData\Roaming\gcloud\credentials.lock in 0 seconds
WARNING: The credentials file (C:\Users\ghousains\AppData\Roaming\gcloud\credentials) is not writable. Opening in read-only mode. Any refreshed credentials will only be valid for this run.
Traceback (most recent call last):
  File "formatter_debug.py", line 133, in <module>
    p.run()
  File "C:\Miniconda3\envs\beam\lib\site-packages\apache_beam\pipeline.py", line 159, in run
    return self.runner.run(self)
    ....
    ....
    ....
  File "C:\Miniconda3\envs\beam\lib\sitepackages\apache_beam\runners\dataflow_runner.py", line 172, in run
    self.dataflow_client.create_job(self.job))    
  StockPickler.save_global(pickler, obj)
  File "C:\Miniconda3\envs\beam\lib\pickle.py", line 754, in save_global (obj, module, name)) 
  pickle.PicklingError: Can't pickle <class 'apache_beam.internal.clients.dataflow.dataflow_v1b3_messages.TypeValueValuesEnum'>: it's not found as apache_beam.internal.clients.dataflow.dataflow_v1b3_messages.TypeValueValuesEnum

3 个答案:

答案 0 :(得分:2)

我发现当Pipeline对象被包含在被pickle并被发送到云端的上下文中时,会引发错误:

pickle.PicklingError: Can't pickle <class 'apache_beam.internal.clients.dataflow.dataflow_v1b3_messages.TypeValueValuesEnum'>: it's not found as apache_beam.internal.clients.dataflow.dataflow_v1b3_messages.TypeValueValuesEnum

当然,您可能会问:

  1. 当Pipeline对象被发送到云端时,是什么让它变得不可用,因为它通常是可以拾取的?
  2. 如果这确实是问题,那么我不会一直得到这个错误 - 不是通常包含在发送到云的上下文中的Pipeline对象吗?
  3. 如果Pipeline对象通常不包含在发送到云端的上下文中,那么为什么我的案例中包含了Pipeline对象?
  4. (1)

    当您使用p.run()在管道上致电cloud=True时,首先发生的事情之一就是在p.runner.job=apiclient.Job(pipeline.options)中设置apache_beam.runners.dataflow_runner.DataflowPipelineRunner.run

    如果没有设置此属性,则管道可以选择。但是一旦设置了这个,管道就不再是可拾取的,因为p.runner.job.proto._Message__tags[17]TypeValueValuesEnum,它被定义为apache_beam.internal.clients.dataflow.dataflow_v1b3_messages中的嵌套类。 AFAIK嵌套类无法被腌制(即使是莳萝 - 请参阅How can I pickle a nested class in python?)。

    (2) - (3)

    违反直觉,Pipeline对象通常不包含在发送到云的上下文中。当您使用p.run()在管道上致电cloud=True时,只会检测以下对象(并注意在p.runner.job设置后进行酸洗):

    1. 如果save_main_session=True,那么指定__main__模块中的所有全局对象都会被腌制。 (__main__是您从命令行运行的脚本。)
    2. 管道中定义的每个转换都是单独腌制的
    3. 在您的情况下,您遇到了#1,这就是您的解决方案有效的原因。我实际上遇到了#2,我将beam.Map lambda函数定义为复合PTransform的方法。 (当应用复合变换时,管道将被添加为变换的属性...)我的解决方案是在模块中定义那些lambda函数。

      长期解决方案是我们在Apache Beam项目中解决这个问题。 TBD!

答案 1 :(得分:1)

我通过在main()方法中封装main的主体并调用run()来解决这个问题。

答案 2 :(得分:1)

这应该在带有https://github.com/apache/incubator-beam/pull/1485的google-dataflow 0.4.4 sdk版本中修复