如何有效地并行化不同的SparkSQL执行?

时间:2018-04-27 06:49:05

标签: scala apache-spark apache-spark-sql

环境

  • Scala的
  • Apache Spark:Spark 2.2.1
  • AWS上的EMR:emr-5.12.1

内容

我有一个大型DataFrame,如下所示:

val df = spark.read.option("basePath", "s3://some_bucket/").json("s3://some_bucket/group_id=*/")

s3://some_bucket有JSON文件〜1TB,它包含5000个group_id分区。 我想使用SparkSQL执行转换,它因每个group_id而不同。

Spark代码如下:

// Create view
val df = spark.read.option("basePath", "s3://data_lake/").json("s3://data_lake/group_id=*/")
df.createOrReplaceTempView("lakeView")

// one of queries like this:
// SELECT 
//   col1 as userId,
//   col2 as userName,
//   .....
// FROM
//   lakeView
// WHERE
//   group_id = xxx;
val queries: Seq[String] = getGroupIdMapping

// ** Want to know better ways **
queries.par.foreach(query => {
  val convertedDF: DataFrame = spark.sql(query)
  convertedDF.write.save("s3://another_bucket/")
})

par可以Runtime.getRuntime.availableProcessors num并行化,它将等于驱动程序核心数。

但这似乎很奇怪而且效率不高,因为它与Spark的并行化毫无关系。

我真的想在groupBy中使用scala.collection.Seq之类的内容。

这不是正确的火花代码:

df.groupBy(groupId).foreach((groupId, parDF) => {
  parDF.createOrReplaceTempView("lakeView")
  val convertedDF: DataFrame = spark.sql(queryByGroupId)
  convertedDF.write.save("s3://another_bucket")
})

1 个答案:

答案 0 :(得分:2)

1)首先,如果您的数据已经存储在每个组ID的文件中,则没有理由将其混合,然后使用Spark按ID进行分组。 为每个组ID加载相关文件

更简单有效

2)Spark本身并行计算。因此在大多数情况下,不需要外部并行化。 但如果你觉得Spark没有利用所有资源,你可以:

a)如果每个单独的计算花费的时间少于几秒,则任务调度开销与任务执行时间相当,因此可以通过并行运行少量任务来获得提升。

b)计算需要大量时间,但资源仍然未得到充分利用。那么很可能你应该增加数据集的分区数。

3)如果你最终决定并行运行几个任务,可以通过这种方式实现:

yarn run encore dev