我有一个HadoopRDD,我从中创建了第一个带有简单Map功能的RDD,然后用第一个RDD创建了第二个RDD,带有另一个简单的Map功能。类似的东西:
HadoopRDD - > RDD1 - > RDD2。
我的问题是Spak是否会通过记录迭代HadoopRDD记录以生成RDD1然后它将按记录迭代RDD1记录以生成RDD2,或者它是否通过HadoopRDD进行整合然后一次生成RDD1然后生成RDD2。
答案 0 :(得分:3)
简答:rdd.map(f).map(g)
将一次性执行。
Spark将作业分成几个阶段。应用于数据分区的阶段是任务。
在一个阶段,Spark将尝试管理尽可能多的操作。 “可能”取决于重新排列数据的需要:需要改组的操作通常会打破管道并创建一个新阶段。
实际上:
Given `rdd.map(...).map(..).filter(...).sort(...).map(...)`
将导致两个阶段:
.map(...).map(..).filter(...)
.sort(...).map(...)
可以使用rdd.toDebugString
从rdd检索
上面的相同工作示例将产生此输出:
val mapped = rdd.map(identity).map(identity).filter(_>0).sortBy(x=>x).map(identity)
scala> mapped.toDebugString
res0: String =
(6) MappedRDD[9] at map at <console>:14 []
| MappedRDD[8] at sortBy at <console>:14 []
| ShuffledRDD[7] at sortBy at <console>:14 []
+-(8) MappedRDD[4] at sortBy at <console>:14 []
| FilteredRDD[3] at filter at <console>:14 []
| MappedRDD[2] at map at <console>:14 []
| MappedRDD[1] at map at <console>:14 []
| ParallelCollectionRDD[0] at parallelize at <console>:12 []
现在,谈谈你的问题的关键点:流水线非常有效。完整的管道将应用于每个分区的每个元素一次。这意味着rdd.map(f).map(g)
的执行速度与rdd.map(f andThen g)
一样快(有一些可忽略的开销)
答案 1 :(得分:0)
Apache Spark将按照没有特定顺序的记录迭代HadoopRDD记录(数据将被拆分并发送给工作人员)并且&#34;应用&#34;计算RDD1的第一个转换。之后,第二次转换应用于RDD1的每个元素以获得RDD2,再次没有特定的顺序,依此类推以进行连续的转换。您可以从map
方法签名中注意到它:
// Return a new RDD by applying a function to all elements of this RDD.
def map[U](f: (T) ⇒ U)(implicit arg0: ClassTag[U]): RDD[U]
Apache Spark遵循DAG(定向非循环图)执行引擎。在需要值之前,它实际上不会触发任何计算,因此您必须区分transformations和actions。
编辑:
就性能而言,我并不完全了解Spark的底层实现,但我知道除了在相关阶段添加额外(不必要的)任务之外,不应该有重大的性能损失。根据我的经验,你通常不会使用相同&#34;自然的变换&#34;连续(在这种情况下连续两次map
)。在进行洗牌操作时,您应该更关注性能,因为您正在移动数据,这会对您的工作绩效产生明显影响。 Here您可以找到与此相关的常见问题。