我是该项目的新手,我正在尝试在Dataflow和数据库之间创建一个连接器.
文档明确指出我应该使用Source和Sink但我看到很多人直接使用与PInput或PDone相关联的PTransform.
源/接收器API处于实验阶段(使用PTransform解释所有示例),但似乎更容易将其与自定义运行器集成(例如:spark).
如果我参考代码,则使用这两种方法.我看不到任何使用PTransform API会更有趣的用例.
Source/Sink API是否应该重新设计PTranform API?
我是否遗漏了能明确区分这两种方法的东西?
Source/Sink API是否足够稳定,被认为是编码输入和输出的好方法?
谢谢你的建议!
Dataflow的哲学是PTransform
抽象和可组合性的主要单元,即任何自包含的数据处理任务都应该封装为PTransform
.这包括连接到第三方存储系统的任务:从某个地方摄取数据或将其导出到某个地方.
以Google Cloud Datastore为例.在代码段中:
PCollectionentities = p.apply(DatastoreIO.readFrom(dataset, query)); ... p.apply(some processing) .apply(DatastoreIO.writeTo(dataset));
返回类型DatastoreIO.readFrom(dataset, query)
是子类PTransform
,而类型DatastoreIO.writeTo(dataset)
是子类PTransform
.
确实,这些函数是使用Source
和Sink
类实现的,但对于只想向Datastore读取或写入内容的用户而言,这是一个通常无关紧要的实现细节(但是,请参阅最后的注释)关于揭露Source
或Sink
类的答案).任何连接器,或者就此而言,任何其他数据处理任务都是PTransform
.
注意:目前从某处读取的连接器往往是PTransform
,并且写入某处的连接器往往是PTransform
,但我们正在考虑选项,以便以更灵活的方式更容易地使用连接器(例如,从PCollection
文件名中读取).
但是,当然,这个细节对于想要实现新连接器的人来说很重要.特别是,您可能会问:
问:如果我可以将连接器实现为PTransform,为什么我需要Source
和Sink
类?
答:如果你可以只使用内置的变换(如实现你的连接器ParDo
,GroupByKey
等等),这是建立一个连接一个完全有效的方式.但是,Source
和Sink
类提供了一些低级功能,如果您需要它们,将会很麻烦或不可能自己开发.
例如,BoundedSource
并UnboundedSource
提供用于控制并行化如何发生的钩子(初始和动态工作重新平衡 - BoundedSource.splitIntoBundles
,BoundedReader.splitAtFraction
),而这些钩子当前没有暴露于任意DoFn
s.
您可以通过编写DoFn
以文件名作为输入,读取文件并发出的文件格式来实现文件格式的解析器SomeRecord
,但是DoFn
如果文件结果是这样,则无法动态地将文件的部分读取到多个工作程序上在运行时非常大.另一方面,FileBasedSource
内置此功能,以及处理glob文件模式等.
同样,您可以尝试通过实现一个DoFn
将虚拟元素作为输入,建立连接并将所有元素流入ProcessingContext.output()
,但DoFn
目前不支持从单个包中写入无限量的输出来实现流式系统的连接器,也不他们是否明确支持Dataflow为流媒体管道提供的强一致性保证所需的检查点和重复数据删除机制.UnboundedSource
另一方面,支持所有这一切.
Sink
(更准确地说,Write.to()
PTransform
)也很有趣:它只是一个复合变换,你可以自己编写,如果你想(即它在Dataflow运行器或后端没有硬编码支持),但它是在考虑典型的情况下开发的在将数据并行写入存储系统时出现的分布式容错问题,它提供了一些钩子,迫使您记住这些问题:例如,因为数据捆绑是并行编写的,并且可能会重试或复制某些捆绑包容错,有一个钩子,用于"提交"成功完成的bundle(WriteOperation.finalize
)的结果.
总结一下:使用Source
或Sink
API开发连接器有助于您以一种在分布式处理设置中良好运行的方式构建代码,并且源API使您可以访问框架的高级功能.但是如果你的连接器是一个非常简单的连接器,那么你可以自由地从其他内置变换中组装你的连接器.
问:假设我决定使用Source
和Sink
.然后我如何打包我的连接器作为库:我应该只提供Source
或Sink
类,或者我应该将它包装成PTransform
?
答:您的连接器最终应打包为a PTransform
,以便用户可以将p.apply()
其放入管道中.但是,在引擎盖下,您的转换可以使用Source
和Sink
类.
一个常见的模式是公开Source
和Sink
类,使用Fluent Builder模式,让用户将它们包装成Read.from()
或Write.to()
转换为自己,但这不是一个严格的要求.