繁体   English   中英

在Apache Spark协作组中,如何确保不移动大于2个操作数的1个RDD?

[英]In Apache Spark cogroup, how to make sure 1 RDD of >2 operands is not moved?

在协同分组转换中,例如RDD1.cogroup(RDD2,...),我曾经假设Spark在以下情况下只会随机播放/移动RDD2并保留RDD1的分区和内存中存储:

  1. RDD1有一个明确的分区程序
  2. RDD1已缓存。

在我的其他项目中,大多数改组行为似乎都与该假设一致。 所以昨天我写了一个简短的scala程序来一劳永逸地证明它:

// sc is the SparkContext
val rdd1 = sc.parallelize(1 to 10, 4).map(v => v->v)
  .partitionBy(new HashPartitioner(4))
rdd1.persist().count()
val rdd2 = sc.parallelize(1 to 10, 4).map(v => (11-v)->v)

val cogrouped = rdd1.cogroup(rdd2).map {
  v =>
    v._2._1.head -> v._2._2.head
}

val zipped = cogrouped.zipPartitions(rdd1, rdd2) {
  (itr1, itr2, itr3) =>
    itr1.zipAll(itr2.map(_._2), 0->0, 0).zipAll(itr3.map(_._2), (0->0)->0, 0)
      .map {
        v =>
          (v._1._1._1, v._1._1._2, v._1._2, v._2)
      }
}

zipped.collect().foreach(println)

如果rdd1不移动,则压缩的第一列应与第三列具有相同的值,所以我运行了程序,哎呀:

(4,7,4,1)
(8,3,8,2)
(1,10,1,3)
(9,2,5,4)
(5,6,9,5)
(6,5,2,6)
(10,1,6,7)
(2,9,10,0)
(3,8,3,8)
(7,4,7,9)
(0,0,0,10)

该假设是不正确的。 Spark可能进行了一些内部优化,并决定重新生成rdd1的分区比将其保留在缓存中要快得多。

因此,问题是:如果我的编程要求不移动RDD1(并使其保持高速缓存)是由于速度以外的其他原因(例如资源局部性),或者在某些情况下Spark内部优化不是可取的,那么有没有一种方法可以明确地指示在所有类似cogroup的操作中不移动操作数的框架? 这也包括联接,外部联接和groupWith。

非常感谢你的帮助。 到目前为止,我使用广播联接作为一种不太可扩展的临时解决方案,它在崩溃集群之前不会持续很长时间。 我期待一个与分布式计算原理一致的解决方案。

如果rdd1不移动,则压缩的第一列应与第三列具有相同的值

这个假设是不正确的。 创建CoGroupedRDD不仅与CoGroupedRDD有关,而且与生成匹配相应记录所需的内部结构有关。 在内部,Spark将使用其自己的ExternalAppendOnlyMap ,它使用自定义开放哈希表实现( AppendOnlyMap ),该实现不提供任何排序​​保证。

如果检查调试字符串:

zipped.toDebugString
(4) ZippedPartitionsRDD3[8] at zipPartitions at <console>:36 []
 |  MapPartitionsRDD[7] at map at <console>:31 []
 |  MapPartitionsRDD[6] at cogroup at <console>:31 []
 |  CoGroupedRDD[5] at cogroup at <console>:31 []
 |  ShuffledRDD[2] at partitionBy at <console>:27 []
 |      CachedPartitions: 4; MemorySize: 512.0 B; ExternalBlockStoreSize: 0.0 B; DiskSize: 0.0 B
 +-(4) MapPartitionsRDD[1] at map at <console>:26 []
    |  ParallelCollectionRDD[0] at parallelize at <console>:26 []
 +-(4) MapPartitionsRDD[4] at map at <console>:29 []
    |  ParallelCollectionRDD[3] at parallelize at <console>:29 []
 |  ShuffledRDD[2] at partitionBy at <console>:27 []
 |      CachedPartitions: 4; MemorySize: 512.0 B; ExternalBlockStoreSize: 0.0 B; DiskSize: 0.0 B
 +-(4) MapPartitionsRDD[1]...

您会看到Spark确实使用CachedPartitions来计算zipped RDD 如果您还跳过map转换,从而删除了分区程序,则会看到coGroup重用了rdd1提供的分区rdd1

rdd1.cogroup(rdd2).partitioner == rdd1.partitioner
Boolean = true

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM