我是spark和scala的新手,刚刚编写了一些Scala代码,用四个密钥对RDD中的数据进行分组,总计五分之一。我的目的是复制这个SQL语句:
SELECT iso, id1, id2, convert(thresh), sum(area::double)
FROM my_table
GROUP BY iso, id1, id2, convert(thresh)
我的scala代码如下,其中finalRDD
是RDD,而convert
是一个简单的函数,用于从1-100中整数:
finalRDD
.map({case Array(lon, lat, thresh, area, iso, id1, id2) => ((iso, id1, id2, convert(thresh)), (area.toDouble)) })
.reduceByKey(_+_)
.map({ case (key, value) => Array(key._1, key._2, key._3, key._4, value)
.mkString(",")})
.saveAsTextFile(conf.get("output.path"))
当我在大型数据集(3.5 TB,并行化为113,000个任务)上运行此过程时,前30,000个任务在一两秒内完成。然而,一小时后,每项任务需要15-20分钟才能完成。
我在AWS EMR上使用13台d2.8xlarge计算机(244 GB内存和36个内核)在Spark 2.0.0中运行此操作。我使用:
运行.jar spark-submit --master yarn --executor-memory 20g --jars my_jar.jar
Spark UI报告所有任务都在相对较快地完成(3 - 5秒),但它确实显示出越来越多的调度程序延迟时间,其中最大的是23分钟。
这是否是每项任务完成时间增加的可能原因?有没有办法更好地构建我的代码(或配置)来避免这种情况? reduByKey是责备吗?
---更新---
我已经更新了我的代码以利用Spark Dataframes,让Spark确定了对我的数据进行分组和汇总的最佳执行计划。更新后的代码如下:
case class TableRow(iso: String, id1: String, id2: String, thresh: Long, area: Double)
finalRDD
.map({case Array(lon, lat, thresh, area, iso, id1, id2) => (TableRow(iso, id1, id2, matchTest(thresh), area.toDouble)) })
.toDF()
.groupBy("iso", "id1", "id2", "thresh").agg(sum("area").alias("area_out"))
.write
.format("csv")
.save(conf.get("output.path"))
运行此更新代码时,我没有遇到调度程序延迟错误,这很好。我确实遇到了连接到执行程序并让它们超时的错误。我已经在这个d2.8xlarge群集上花了相当多的时间和金钱,最后我将我的工作分成了14个独立的工作,这些工作都成功完成了。