我在尝试将DF转换为RDD时遇到了问题。这个过程中的一个阶段总共使用了200个任务,而在此之前的大多数部分使用了更多,并且我无法理解为什么它使用这个数字以及我是否需要找到一种方法来增加这个以提高性能
该程序使用Spark版本2.1.0,并在我使用250个执行程序的Yarn集群上运行。
这些是DF转换为RDD的行:
val predictionRdd = selectedPredictions
.withColumn("probabilityOldVector", convertToOldVectorUdf($"probability"))
.select("mid", "probabilityOldVector")
.rdd
这导致前面提到的200个任务,如以下屏幕截图中的活动阶段所示。
它基本上只是卡在这里因为我不知道多长时间,其他两个完成的阶段使用了更多的任务。
我尝试过的一件事就是在将其转换为RDD之前执行重新分区:
val predictionRdd = selectedPredictions
.withColumn("probabilityOldVector", convertToOldVectorUdf($"probability"))
.select("mid", "probabilityOldVector")
.repartition(2000)
.rdd
val avgPredictions = predictionRdd
.map(row => (row.getAs[String]("mid"), row.getAs[OldVector]("probabilityOldVector")))
.aggregateByKey(new MultivariateOnlineSummarizer)(
(agg, v) => agg.add(v),
(agg1, agg2) => agg1.merge(agg2)
)
.map(p => (p._1, p._2.mean))
假设理想情况下,这将导致执行2000个任务。然而,这有一个(对我来说)意想不到的结果。 This图像(与之前相同)显示该部分所属的整个作业。有趣的是,它仍然显示200个任务,并且在将其转换为RDD之前的重新分区的2000个分区在用于挂起的地图阶段的任务数量中可见。
我觉得要提高这部分的速度,我需要增加正在执行的任务的数量,允许它以更少的内存和更少的内存并行运行。
所以我的问题基本上是:
我仍然是Spark的新手,我在更高层次上了解我的方式,但实际的错综复杂仍然无法实现。
在撰写本文时,我注意到它在大约1.3小时后显示出一些进展,看似简单。
以下是执行者和任务的聚合指标的一小部分:
Executor ID Address Task Time Total Tasks Failed Tasks Killed Tasks Succeeded Tasks Shuffle Read Size / Records Shuffle Write Size / Records Shuffle Spill (Memory) Shuffle Spill (Disk)
1 - 1.4 h 1 0 0 1 1810.3 MB / 8527038 2.1 GB / 2745175 5.9 GB 1456.3 MB
10 - 0 ms 0 0 0 0 1808.2 MB / 8515093 0.0 B / 1839668 5.9 GB 1456.7 MB
和
Index ID Attempt Status Locality Level Executor ID / Host Launch Time Duration Scheduler Delay Task Deserialization Time GC Time Result Serialization Time Getting Result Time Peak Execution Memory Shuffle Read Size / Records Write Time Shuffle Write Size / Records Shuffle Spill (Memory) Shuffle Spill (Disk) Errors
0 19454 0 RUNNING PROCESS_LOCAL 197 / worker176.hathi.surfsara.nl 2017/05/29 17:23:37 1.5 h 0 ms 0 ms 3.8 min 0 ms 0 ms 3.1 GB 1809.9 MB / 8525371 0.0 B / 1839667 5.9 GB 1456.0 MB
1 19455 0 SUCCESS PROCESS_LOCAL 85 / worker134.hathi.surfsara.nl 2017/05/29 17:23:37 1.5 h 42 ms 8 s 3.2 min 0 ms 0 ms 6.0 GB 1808.3 MB / 8519686 5 s 2.1 GB / 2742924 5.9 GB 1456.3 MB
以下是上下文的其他几个屏幕截图,作为链接添加,以免使这篇文章过长:
第45和46阶段在47之前同时运行。源代码的主要部分可以在GitHub上的this代码段中查看。它会加载以前经过培训的CrossValidatorModel
,其中包含一个包含五个步骤的管道:CharNGram
,CountVectorizer
,IDF
,RandomForestClassifier
和IndexToString
。它预测了大约5.5亿个文本片段的200个类的概率,最大长度为550个字符。然后将这些预测按输入类组合在一起,然后进行平均。
答案 0 :(得分:2)
您可以使用以下方式设置任务数量:
val spConfig = (new SparkConf).setMaster("local[*]").setAppName("MoviesRec")
// Spark UI available at port 4040.. check here also
spark = SparkSession.builder().appName("Movies").config(spConfig)
.config("spark.ui.enabled", true)
.config("spark.sql.shuffle.partitions", "100")
在日志中,您将获得以下内容:[Stage 9:======================================================> (98 + 2) / 100]
200是数据帧的默认值。
您也可以在SparkUI上的localhost:4040上查看它,检查分区数,每个分区的大小以及您拥有的总RAM。
在我的桌面上,如果我将默认的分区数从200减少到8(我拥有的核心数),那么它真的很快。但是,如果partition = nr的内核可能过于简单,因为分区代表一个数据块(默认为64MB)。所以人们应该走上阶梯,直到至少使用整个记忆。