繁体   English   中英

Spark RDD - 它们是如何工作的

[英]Spark RDD's - how do they work

我有一个小型Scala程序,可以在单个节点上运行。 但是,我正在扩展它,因此它在多个节点上运行。 这是我的第一次尝试。 我只是想了解RDD如何在Spark中工作,所以这个问题是基于理论的,可能不是100%正确。

假设我创建了一个RDD: val rdd = sc.textFile(file)

现在,一旦我这样做了,这是否意味着文件中的file现在已经跨节点分区(假设所有节点都可以访问文件路径)?

其次,我想计算RDD中的对象数量(足够简单),但是,我需要在需要应用于RDD中的对象的计算中使用该数字 - 伪代码示例:

rdd.map(x => x / rdd.size)

假设rdd有100个对象,并且说有10个节点,因此每个节点计数10个对象(假设这是RDD概念的工作原理),现在当我调用该方法时,每个节点都要执行计算rdd.size10100 因为,总体而言,RDD的大小为100但每个节点本地只有10 我是否需要在进行计算之前制作广播变量? 这个问题与下面的问题有关。

最后,如果我转换到RDD,例如rdd.map(_.split("-")) ,然后我想要RDD的新size ,我是否需要对RDD执行操作,例如count() ,所有信息都被发送回驱动程序节点?

 val rdd = sc.textFile(file) 

这是否意味着文件现在跨节点分区?

该文件保留在任何地方。 生成的RDD[String]的元素是文件的行。 RDD被分区以匹配底层文件系统的自然分区。 分区数不依赖于您拥有的节点数。

重要的是要理解,当执行此行时,它不会读取文件。 RDD是一个懒惰的对象,只有在必要时才会执行某些操作。 这很好,因为它避免了不必要的内存使用。

例如,如果你写val errors = rdd.filter(line => line.startsWith("error")) ,仍然没有任何反应。 如果你现在写了val errorCount = errors.count那么你需要执行你的操作序列,因为count的结果是一个整数。 然后,每个工作者核心(执行程序线程)并行执行的操作是读取文件(或文件片段),遍历其行,并计算以“错误”开头的行。 除了缓冲和GC之外,每个核心只有一行将一次存储在内存中。 这使得可以在不使用大量内存的情况下处理非常大的数据。

我想计算RDD中的对象数量,但是,我需要在计算中使用该数字,该计算需要应用于RDD中的对象 - 伪代码示例:

 rdd.map(x => x / rdd.size) 

没有rdd.size方法。 rdd.count ,它计算RDD中的元素数量。 rdd.map(x => x / rdd.count)不起作用。 代码将尝试将rdd变量发送给所有worker,并且会因NotSerializableException而失败。 你能做的是:

val count = rdd.count
val normalized = rdd.map(x => x / count)

这是有效的,因为count是一个Int并且可以序列化。

如果我转换到RDD,例如rdd.map(_.split("-")) ,然后我想要RDD的新大小,我是否需要对RDD执行操作,例如count() ,所有的信息都被发送回驱动程序节点?

map不会更改元素的数量。 我不知道你的“大小”是什么意思。 但是,是的,您需要执行一个操作,例如count以从RDD中获取任何内容。 你看,在你执行一个动作之前,根本不会执行任何工作。 (当您执行count ,只有每个分区计数将被发送回驱动程序,当然,不是“所有信息”。)

通常,文件(或文件的一部分,如果它太大)被复制到集群中的N个节点(默认情况下,HDFS上的N = 3)。 并不打算在所有可用节点之间拆分每个文件。

但是,对于您(即客户端)使用Spark处理文件应该是透明的 - 您不应该看到rdd.size任何区别,无论它分割和/或复制多少个节点。 有一些方法(至少在Hadoop中)可以找出目前可以找到哪些节点(部分)文件。 但是,在简单的情况下,您很可能不需要使用此功能。

更新:描述RDD内部的文章: https//cs.stanford.edu/~matei/papers/2012/nsdi_spark.pdf

暂无
暂无

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

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