Google cloud dataflow 是否可以在ApacheBeam中对两个PCollection执行zip操作?

Google cloud dataflow 是否可以在ApacheBeam中对两个PCollection执行zip操作?,google-cloud-dataflow,apache-beam,Google Cloud Dataflow,Apache Beam,我有一个PCollection[str],我想生成随机对 来自Apache Spark,我的策略是: 复制原始PCollection 随机洗牌 使用原始PCollection将其压缩 但是,我似乎找不到压缩2个PCollection的方法…如何将转换应用于将键附加到元素的两个PCollection,并通过转换运行这两个PCollection 请注意,Beam不能保证PCollection中元素的顺序,因此输出元素可能在任何步骤后都会重新排序,但这似乎适合您的用例,因为您只需要一些随机顺序。对两个

我有一个PCollection[str],我想生成随机对

来自Apache Spark,我的策略是:

复制原始PCollection 随机洗牌 使用原始PCollection将其压缩 但是,我似乎找不到压缩2个PCollection的方法…

如何将转换应用于将键附加到元素的两个PCollection,并通过转换运行这两个PCollection

请注意,Beam不能保证PCollection中元素的顺序,因此输出元素可能在任何步骤后都会重新排序,但这似乎适合您的用例,因为您只需要一些随机顺序。

对两个将键附加到元素的PCollection应用转换并运行两个PCollection如何通过转变


请注意,Beam并不能保证PCollection中元素的顺序,因此输出元素可能在任何步骤后都会重新排序,但这似乎适合您的用例,因为您只需要一些随机顺序。

这是一个有趣且不太常见的用例,因为正如@chamikara所说,数据流中没有订单保证。但是,我考虑过实现一个解决方案,在该解决方案中,您洗牌输入PCollection,然后根据输入对连续元素进行配对。我发现了一些注意事项,但我认为还是值得分享的

首先,我使用了Python SDK,但Dataflow Runner还不支持有状态的DoFn。它与Direct Runner一起工作,但是:1它不可伸缩,2如果没有多线程,很难洗牌记录。当然,对于后者来说,一个简单的解决方案是将已经洗牌的PCollection提供给管道,我们可以使用不同的作业来预处理数据。否则,我们可以将此示例改编为JavaSDK

现在,我决定尝试洗牌并将其与单个管道配对。我真的不知道这是否有帮助或使事情变得更复杂,但可以找到代码

简单地说,有状态DoFn查看缓冲区,如果缓冲区为空,则将其放入当前元素。否则,它会从缓冲区中弹出前一个元素,并输出前一个元素的元组,即当前元素:

类PairRecordsFnbeam.DoFn: 洗牌后配对两个连续元素 BUFFER=BagStateSpec'BUFFER',pickle编码器 def processself,元素,buffer=beam.DoFn.StateParamBUFFER: 尝试: 上一个元素=listbuffer.read[0] 除: 上一个_元素=[] 未使用的_键,值=元素 如果前一个_元素: 产生上一个元素、值 缓冲区,清除 其他: buffer.addvalue 管道根据需要向输入元素添加键以使用有状态DoFn。这里会有一个折衷方案,因为您可能会使用beam.Maplambda x:1,x为所有元素分配相同的键。这不会很好地并行化,但这不是问题,因为我们使用的是Direct Runner,如果使用Java SDK,请记住这一点。但是,它不会洗牌记录。相反,如果我们洗牌到大量的键,我们将得到大量无法配对的孤立元素,因为每个键的状态保持不变,我们随机分配它们,每个键可以有奇数个记录:

成对=p |“创建事件”>>beam.Createdata |“添加关键点”>>beam.Maplambda x:randint1,4,x |“配对记录”>>beam.pardopairecordsfn |“检查结果”>>beam.ParDoLogFn 在我的例子中,我得到了如下结果:

信息:根:'1','3' 信息:根:'2','5' 信息:根:'0','6' 信息:根:'four','seven' 信息:根:'十','十二' 信息:根:“九”,“十三” 信息:根:'8','14' 信息:根:'11','16' ... 编辑:我想到了使用Sample.FixedSizeGlobally合并器的另一种方法。好的方面是,它可以更好地洗牌数据,但您需要事先知道元素的数量,否则我们需要对数据进行初始传递,它似乎会将所有元素一起返回。简单地说,我初始化同一个PCollection两次,但应用不同的洗牌顺序,并在有状态DoFn中分配索引。这将保证索引在同一个PCollection中的元素之间是唯一的,即使不保证顺序也是如此。在我的例子中,对于[0,31]范围内的每个键,两个PCollection都将有一条记录。CoGroupByKey转换将在同一索引上连接两个PCollection,因此具有随机的元素对:

pc1=p |“创建事件1”>>beam.Createdata |'Sample 1'>>combine.Sample.FixedSizeGloballyNUM_元素 |“拆分样本1”>>beam.ParDoSplitFn |'添加虚拟键1'>>beam.Maplambda x:1,x |'分配索引1'>>beam.ParDoIndexAssigningStatefulDoFn pc2=p |“创建事件2”>>beam.Createdata |'Sample 2'>>combine.Sample.FixedSizeGloballyNUM_元素 |“拆分样本2”>>beam.ParDoSplitFn |'添加虚拟键2'>>beam.Maplambda x:2,x |'分配索引2'>>beam.ParDoIndexAssigningStatef 奥多夫 压缩=pc1,pc2 |'Zip Shuffled PCollections'>>beam.CoGroupByKey |'下降指数'>>光束.映射λx,y:y |“检查结果”>>beam.ParDoLogFn 完整代码

结果:

信息:根:['ten'],['think'] 信息:root:['二十三'],['七'] 信息:root:['二十五'],['二十'] 信息:根:['十二],['二十一'] 信息:root:['二十六],['二十五'] 信息:root:['zero'],['二十三'] ...
这是一个有趣且不太常见的用例,因为正如@chamikara所说,数据流中没有订单保证。但是,我考虑过实现一个解决方案,在该解决方案中,您洗牌输入PCollection,然后根据输入对连续元素进行配对。我发现了一些注意事项,但我认为还是值得分享的

首先,我使用了Python SDK,但Dataflow Runner还不支持有状态的DoFn。它与Direct Runner一起工作,但是:1它不可伸缩,2如果没有多线程,很难洗牌记录。当然,对于后者来说,一个简单的解决方案是将已经洗牌的PCollection提供给管道,我们可以使用不同的作业来预处理数据。否则,我们可以将此示例改编为JavaSDK

现在,我决定尝试洗牌并将其与单个管道配对。我真的不知道这是否有帮助或使事情变得更复杂,但可以找到代码

简单地说,有状态DoFn查看缓冲区,如果缓冲区为空,则将其放入当前元素。否则,它会从缓冲区中弹出前一个元素,并输出前一个元素的元组,即当前元素:

类PairRecordsFnbeam.DoFn: 洗牌后配对两个连续元素 BUFFER=BagStateSpec'BUFFER',pickle编码器 def processself,元素,buffer=beam.DoFn.StateParamBUFFER: 尝试: 上一个元素=listbuffer.read[0] 除: 上一个_元素=[] 未使用的_键,值=元素 如果前一个_元素: 产生上一个元素、值 缓冲区,清除 其他: buffer.addvalue 管道根据需要向输入元素添加键以使用有状态DoFn。这里会有一个折衷方案,因为您可能会使用beam.Maplambda x:1,x为所有元素分配相同的键。这不会很好地并行化,但这不是问题,因为我们使用的是Direct Runner,如果使用Java SDK,请记住这一点。但是,它不会洗牌记录。相反,如果我们洗牌到大量的键,我们将得到大量无法配对的孤立元素,因为每个键的状态保持不变,我们随机分配它们,每个键可以有奇数个记录:

成对=p |“创建事件”>>beam.Createdata |“添加关键点”>>beam.Maplambda x:randint1,4,x |“配对记录”>>beam.pardopairecordsfn |“检查结果”>>beam.ParDoLogFn 在我的例子中,我得到了如下结果:

信息:根:'1','3' 信息:根:'2','5' 信息:根:'0','6' 信息:根:'four','seven' 信息:根:'十','十二' 信息:根:“九”,“十三” 信息:根:'8','14' 信息:根:'11','16' ... 编辑:我想到了使用Sample.FixedSizeGlobally合并器的另一种方法。好的方面是,它可以更好地洗牌数据,但您需要事先知道元素的数量,否则我们需要对数据进行初始传递,它似乎会将所有元素一起返回。简单地说,我初始化同一个PCollection两次,但应用不同的洗牌顺序,并在有状态DoFn中分配索引。这将保证索引在同一个PCollection中的元素之间是唯一的,即使不保证顺序也是如此。在我的例子中,对于[0,31]范围内的每个键,两个PCollection都将有一条记录。CoGroupByKey转换将在同一索引上连接两个PCollection,因此具有随机的元素对:

pc1=p |“创建事件1”>>beam.Createdata |'Sample 1'>>combine.Sample.FixedSizeGloballyNUM_元素 |“拆分样本1”>>beam.ParDoSplitFn |'添加虚拟键1'>>beam.Maplambda x:1,x |'分配索引1'>>beam.ParDoIndexAssigningStatefulDoFn pc2=p |“创建事件2”>>beam.Createdata |'Sample 2'>>combine.Sample.FixedSizeGloballyNUM_元素 |“拆分样本2”>>beam.ParDoSplitFn |'添加虚拟键2'>>beam.Maplambda x:2,x |'分配索引2'>>beam.ParDoIndexAssigningStatefulDoFn 压缩=pc1,pc2 |'Zip Shuffled PCollections'>>beam.CoGroupByKey |'下降指数'>>光束.映射λx,y:y |“检查结果”>>beam.ParDoLogFn 完整代码

结果:

信息:根:['ten'],['think'] 信息:root:['二十三'],['七'] 信息:root:['二十五'],['二十'] 信息:根:['十二],['二十一'] 信息:root:['二十六],['二十五'] 信息:root:['zero'],['二十三'] ...