Google cloud dataflow 从梁中的另一条管道读取pickle?
我在谷歌云数据流中运行批处理管道。我需要读取一条管道中另一条管道以前编写的对象。最简单的wa对象是pickle/dill 编写工作很好,编写了许多文件,每个文件都有一个pickle对象。当我手动下载该文件时,我可以取消粘贴该文件。写入代码:beam.io.WriteToText'gs://{},coder=coders.DillCoder 但每次读数都会中断,出现以下错误之一。读取代码:beam.io.ReadFromText'gs://{}*',coder=coders.DillCoder 要么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 要
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的情况下才会有帮助。这太棒了!非常感谢你