Google cloud dataflow 从梁中的另一条管道读取pickle?

Google cloud dataflow 从梁中的另一条管道读取pickle?,google-cloud-dataflow,apache-beam,apache-beam-io,Google Cloud Dataflow,Apache Beam,Apache Beam Io,我在谷歌云数据流中运行批处理管道。我需要读取一条管道中另一条管道以前编写的对象。最简单的wa对象是pickle/dill 编写工作很好,编写了许多文件,每个文件都有一个pickle对象。当我手动下载该文件时,我可以取消粘贴该文件。写入代码:beam.io.WriteToText'gs://{},coder=coders.DillCoder 但每次读数都会中断,出现以下错误之一。读取代码:beam.io.ReadFromText'gs://{}*',coder=coders.DillCoder 要

我在谷歌云数据流中运行批处理管道。我需要读取一条管道中另一条管道以前编写的对象。最简单的wa对象是pickle/dill

编写工作很好,编写了许多文件,每个文件都有一个pickle对象。当我手动下载该文件时,我可以取消粘贴该文件。写入代码:beam.io.WriteToText'gs://{},coder=coders.DillCoder

但每次读数都会中断,出现以下错误之一。读取代码:beam.io.ReadFromText'gs://{}*',coder=coders.DillCoder

要么

  File "/usr/local/lib/python2.7/dist-packages/dill/dill.py", line 266, in load
    obj = pik.load()
  File "/usr/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
KeyError: '\x90'
……或者

  File "/usr/local/lib/python2.7/dist-packages/dill/dill.py", line 423, in find_class
    return StockUnpickler.find_class(self, module, name)
  File "/usr/lib/python2.7/pickle.py", line 1124, in find_class
    __import__(module)
ImportError: No module named measur
对象的类位于一个带有measure的路径中,但不确定它为什么遗漏了其中的最后一个字符

我已经尝试使用默认编码器和ByteCoder,并将酸洗和取消酸洗作为管道中的自定义任务

我的工作假设是读卡器将文件逐行拆分,因此将具有新行的单个pickle视为多个对象。如果是,有没有办法避免这种情况

我可以尝试自己制作一个阅读器,但我犹豫不决,因为这似乎是一个很好解决的问题,例如Beam已经有了一种将对象从一个管道阶段移动到另一个管道阶段的格式

切向相关:

谢谢大家!

编码为string_escape会转义换行符,因此Beam看到的唯一换行符是pickle之间的换行符:

DillMultiCoderDillCoder类: 允许读取多行pickle的编码器 对象被pickle后,字节被编码为“unicode\u escape”, 意思是换行符“\n”不在字符串中。 以前,这些新行字符的存在会混淆数据流 读者,因为它不能区分新对象和新行 束手无策 定义创建自己: 返回编码器\u impl.CallbackCoderImpl 可能是多次转储,可能是多次加载 def可能需要多个转储,因此: 在Py3中,这需要是'unicode\u escape'` 返回maybe\u dill\u dumpso。编码“string\u escape” def可能需要反复加载,因此: 在Py3中,这需要是'unicode\u escape'` 返回maybe\u dill\u loadso。解码“string\u escape” 对于大型pickle,我还需要将buffersize设置为8MB—在以前的缓冲区大小8kB的基础上,一个120MB的文件旋转2天的CPU时间:

类ReadFromTextPickleReadFromText: 与ReadFromText相同,但缓冲区非常大。使用标准8KB 缓冲区,大文件可以在循环中读取,并且永远不会完成 还添加了DillMultiCoder 定义初始化__ 自己 文件模式=无, 最小捆绑大小=0, 压缩类型=压缩类型.AUTO, strip_training_newlines=True, 编码器=DillMultiCoder, 验证=真, 跳过标题行=0, **夸尔格: 需要评论,不知道为什么 superReadFromTextPickle,self.\uuuu init\uuuu**kwargs self.\u source=\u TextSource 文件模式, 最小束大小, 压缩型, strip_training_newlines=strip_training_newlines, 编码器=编码器, 验证, 跳过标题行=跳过标题行, 缓冲区大小=8000000
另一种方法是实现从FileBasedSource继承的PickleFileSource,并对该文件调用pickle.load——每次调用都会生成一个新对象。但是偏移量范围跟踪器有一大堆复杂问题,看起来比严格必要的要复杂得多

ReadFromText设计用于读取文本文件中新的行分隔记录,因此不适合您的用例。实现FileBasedSource也不是一个好的解决方案,因为它是为读取包含多条记录的大型文件而设计的,并且通常将这些文件拆分为碎片以进行并行处理。因此,在您的情况下,Python SDK当前最好的解决方案是自己实现一个源代码。这可以像ParDo读取文件并生成记录的PCollection一样简单。如果您的PARDO产生大量的记录,考虑添加一个ApaseEyBeAM.Turras.UTI.RESHUFFLE步骤,这将允许运行者更好地并行化以下步骤。对于Java SDK,我们已经有了FileIO,它已经提供了转换来简化这一点。

这是一个有趣的建议,可以编写一个简单的阅读器,而不需要FileBasedSource开销。但一个潜在的问题是:PCollection的总大小约为100GB—数据流是否能够处理大于单个ParDo的内存输出?顺便说一句,现有的方法工作正常,尽管我可以想象它效率低下/通常是坏的。Dataflow应该能够处理大型输出。您可能还希望有一个ParDo,它在读取之前分割输入,以便通过为每个读取器提供一个文件子集(例如,在重新排列之后)来并行读取。因此,流可能是将文件集拆分为
组->重新洗牌->读取一组文件并输出的ParDo->重新洗牌。第二次改组是可选的,只有在每个ParDo实例都创建了大量的输出,并且在您的管道中没有GBK的情况下才会有帮助。这太棒了!非常感谢你