在spark中,如何同时运行几个`collect`

时间:2016-11-16 23:52:50

标签: apache-spark pyspark hadoop2 bigdata

我是Spark的新手,我不确定我是否理解分配工作的方式。

我有以下代码:

c1 = dict(smallrdd1.collect())
bigrdd1 = bigrdd1.filter(lambda val: c1[val])

c2 = dict(smallrdd2.collect())
bigrdd2 = bigrdd2.filter(lambda val: c2[val])

如果我理解的话,两个collect将在主要作业上运行,而不是同时运行,这将减慢整个过程。如何让spark在单独的节点上执行收集和过滤单独的作业?

修改

我认为我的问题不是很清楚。我会试着让它更具体。

我想要实现的是一个有效的星图 - 连接面向列的数据。也就是说,我有一些维度表,每个维度表都有几百万个键值。当存储为原始python dict或scala Map时,它们各自为几百Mb。这个小到足以在每个节点上单独存储在内存中,但总之,它们组成了几个Gb,并且不适合内存。

另一方面,对于每个小维度列,我有一个很大的事实列,有几十亿行,肯定不适合内存。

这个想法是管理集群内的数据位置,以便每个大表位于不同的节点上。然后启动几个任务,每个任务负责一个连接。然后从磁盘加载维度表并同时创建哈希映射 ,然后仅将“哈希”广播到需要它的那些任务。然后,将大事实列与维度表连接起来。

2 个答案:

答案 0 :(得分:1)

因此,collecttake上的first通常用于测试和调试。正如@Shankar写的那样,collect会将所有数据提取到驱动程序,这对于测试期间使用的小数据集很好,但在处理大量数据集时却不行,因为它会使用OOM杀死你的驱动程序。 / p>

现在,您说您想要加入,所以只需使用join

val joined = bigrdd.join(smallrdd, bigrdd.col("id") === smallrdd.col("id"))

(这是Scala语法,但我确定你明白了这一点)

现在数据已加入您的工作人员,您可以继续使用过滤器,地图和其他转换:)

答案 1 :(得分:0)

所以,我认为对我的问题的简短回答只是它不可能

从我得到的答案来看,我认为这只是不可能与spark 。我们唯一的可能性是在驱动程序中创建所有的配图,或使用传统的spark join

在驱动程序内

按顺序加载小维度表,然后将它们广播到所有执行者(这是顺序的,并导致无用数据移动的Gbs):

c1 = sc.broadcast(smallrdd1.collectAsMap())
bigrdd1 = bigrdd1.filter(lambda val: c1.value[val])

c2 = sc.broadcast(smallrdd2.collectAsMap())
bigrdd2 = bigrdd2.filter(lambda val: c1.value[val])

在执行者

不计算驱动程序上的任何内容,但计算连接速度较慢,因为它涉及对大型数据集的随机操作。

bigrdd1 = bigrdd1 \
              .map(lambda (bigk,bigv):(bigv,bigk)) \
              .join(smallrdd1) \
              .map(lambda (bigv,(bigk,smallv)):(bigk,bigv))
bigrdd2 = bigrdd2 \
              .map(lambda (bigk,bigv):(bigv,bigk)) \
              .join(smallrdd2) \
              .map(lambda (bigv,(bigk,smallv)):(bigk,bigv))