我有一个数据集(作为RDD
),我使用不同的filter
运算符将其划分为4个RDD。
val RSet = datasetRdd.
flatMap(x => RSetForAttr(x, alLevel, hieDict)).
map(x => (x, 1)).
reduceByKey((x, y) => x + y)
val Rp:RDD[(String, Int)] = RSet.filter(x => x._1.split(",")(0).equals("Rp"))
val Rc:RDD[(String, Int)] = RSet.filter(x => x._1.split(",")(0).equals("Rc"))
val RpSv:RDD[(String, Int)] = RSet.filter(x => x._1.split(",")(0).equals("RpSv"))
val RcSv:RDD[(String, Int)] = RSet.filter(x => x._1.split(",")(0).equals("RcSv"))
我已将Rp
和RpSV
发送到以下函数calculateEntropy
:
def calculateEntropy(Rx: RDD[(String, Int)], RxSv: RDD[(String, Int)]): Map[Int, Map[String, Double]] = {
RxSv.foreach{item => {
val string = item._1.split(",")
val t = Rx.filter(x => x._1.split(",")(2).equals(string(2)))
.
.
}
}
我有两个问题:
1-当我在RxSv
上循环操作时:
RxSv.foreach{item=> { ... }}
它会收集分区的所有项目,但我只想要一个我所在的分区。如果您说用户map
有效,但我不会在RDD
上进行任何更改。
因此,当我在具有4个工作线程和驱动程序的集群上运行代码时,数据集将分为4个分区,每个工作程序都会运行代码。但是例如我使用foreach循环,因为我在代码中指定。司机收集工人的所有数据。
2-我遇到过这段代码的问题
val t = Rx.filter(x => x._1.split(",")(2).equals(abc(2)))
错误:
org.apache.spark.SparkException: This RDD lacks a SparkContext.
在下列情况下可能发生:
(1)RDD
transformations
和actions
不是由驱动程序调用,而是在其他转换中调用;
例如,rdd1.map(x => rdd2.values.count() * x)
无效,因为无法在transformation
count
内执行值action
和rdd1.map
transformation
。有关更多信息,请参阅SPARK-5063。
(2)当Spark Streaming
作业从检查点恢复时,如果在RDD
操作中使用了未由流作业定义的DStream
的引用,则会触发此异常。有关详细信息,请参阅SPARK-13758。
答案 0 :(得分:3)
首先,我强烈建议使用cache
运算符缓存第一个RDD。
RSet.cache
每次filter
用于其他RDD时,这将避免扫描和转换数据集:Rp
,Rc
,RpSv
和RcSv
。
引用cache的scaladoc:
cache()使用默认存储级别(MEMORY_ONLY)保留此RDD。
性能应该提高。
其次,我要非常小心地使用术语"分区"引用过滤的RDD,因为该术语在Spark中具有特殊含义。
分区说明Spark为一个动作执行了多少任务。它们是Spark的提示,因此Spark(Spark开发人员)可以对您的分布式管道进行微调。
管道分布在群集节点上,每个分区方案都有一个或多个Spark执行器。如果您决定在RDD中拥有一个分区,那么在对该RDD执行操作后,您将在一个执行程序上执行一个任务。
filter
转换不会更改分区数(换句话说,它会保留分区)。分区数,即任务数,正是RSet
的分区数。
1-当我在
RxSv
上循环操作时,它会收集分区的所有项目,但我只想要一个我所在的分区
你是。不要担心它,因为Spark将在数据存在的执行器上执行任务。 foreach
是一个执行不收集项目的操作,但描述了在执行程序上运行的计算,其中数据分布在整个群集中(作为分区)。
如果您希望每个分区一次处理所有项目,请使用foreachPartition:
foreachPartition 将函数f应用于此RDD的每个分区。
2-我遇到过这段代码的问题
在以下代码行中:
RxSv.foreach{item => {
val string = item._1.split(",")
val t = Rx.filter(x => x._1.split(",")(2).equals(string(2)))
您正在执行foreach
操作,该操作又使用Rx
RDD[(String, Int)]
。这是不允许的(如果有可能不应该编译)。
行为的原因是RDD是一种数据结构,它只描述了在执行操作并且存在于驱动程序(协调器)上时数据集发生的情况。驱动程序使用数据结构来跟踪数据源,转换和分区数。
当驱动程序在执行程序上生成任务时,RDD作为一个实体消失了(=消失)。
当任务运行时,没有任何东西可以帮助他们知道如何运行属于他们工作的RDD。因而错误。 Spark对此非常谨慎,并在执行任务后可能导致问题之前检查此类异常情况。