Apache spark 在spark中,如何同时运行多个'collect'

Apache spark 在spark中,如何同时运行多个'collect',apache-spark,pyspark,hadoop2,bigdata,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在不同的

我是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,无法装入内存

另一方面,对于这些小维度列中的每一列,我都有一个大的事实列,它有几十亿行,当然不适合内存


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

因此,
collect
沿着
take
first
通常用于测试和调试。正如@Shankar所写的,
collect
会将所有数据拉到驱动程序,这对于测试期间使用的小数据集来说很好,但在处理大数据集时就不好了,因为它会用OOM杀死你的驱动程序

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

val joined = bigrdd.join(smallrdd, bigrdd.col("id") === smallrdd.col("id"))
(这是Scala语法,但我相信您理解了要点)


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

因此,我认为我的问题的简短答案是,这是不可能的

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

司机里面 按顺序加载小维度表,然后将其广播给所有执行器(这是按顺序的,会导致Gbs的无用数据移动):

论遗嘱执行人 不计算驱动程序上的任何内容,但计算联接的速度较慢,因为它涉及到对大型数据集的洗牌操作

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))

两个collect不会同时运行,它是连续的。主要的是当你收集的时候,它会收集所有的元素给驱动,当你使用任何转换或动作,比如过滤器,映射等等。。。它将在不同的节点上运行。是的,我理解。但在我的例子中,我需要将这些
dict
只放在执行过滤器的执行器上。我不需要他们在司机身上。有没有办法做到这一点?我不知道这是什么命令。。。但是为什么你先收集然后过滤呢?当您使用筛选器时,它将在执行器上运行。是的,筛选器当然将在执行器上运行。我正在尝试实现一个并行的map-side连接。这些dict是我的小表的哈希表。是的,当然,我可以使用
join
。但是问题是连接是一个代价高昂的操作,当
smallrdd
足够小时,这是不必要的。您建议的是reduce-side连接,我想做一个map-side连接。如果我理解正确,spark不会用我的小rdd自动构建hashmap,但如果我使用
join
,它会在后台执行代价高昂的洗牌操作。我说的对吗?听着,我们正试图帮助你,但你显然知道得最好,所以我不确定,为什么你会在这里发布这样的帖子。我可以告诉你,我已经使用Spark两年了,如果你看看我的个人资料,你会发现我96%的声誉都来自于回答Spark的问题,所以我对Spark编程有一点了解。要并行化查询,您需要使用
join
。如果您的smallrdd非常小,为什么还要将其作为rdd加载?只需使用一个普通的数组并播放它。如果我看起来有攻击性,我真的很抱歉,这不是目标!每个smallrdd都足够小,可以放在内存中,但可能
smallrdd1
+
smallrdd2
不适合。只广播一个,然后广播另一个的问题是它是连续的。我想知道是否有一种并行的方法。SmallRDD必须装入一个常规数组才能进行广播。如果它们不能,那么您的SmallRDD就没有那么小了,您需要进行一次
连接。确实,
join
会导致数据混乱,但是Spark就是为此而构建的,它真的很擅长于此。当然,您应该小心移动的数据量,并确保不会多次移动相同的数据,但大多数工作都需要移动。你的工作不是避免洗牌,而是避免不必要的洗牌。我担心你不会在这里得到我的支持票。你想做的,根本不是你如何在Spark中做事,而是你没有接受这一点并接受Spark的方式,你似乎坚持收集RDD作为首选解决方案的想法。。。我非常不同意这一点——不知道还能说些什么。如果我看起来很固执或者让你浪费时间,我真的很抱歉。但我真的想在这里实现一个算法,不仅仅是为了完成任务。对于那些感兴趣的人,我仍然在我的答案中加入了工作火花代码。我还能做什么?
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))