Scala 如何有效地并行不同的SparkSQL执行? 环境 斯卡拉 ApacheSpark:Spark 2.2.1 AWS上的EMR:EMR-5.12.1 内容

Scala 如何有效地并行不同的SparkSQL执行? 环境 斯卡拉 ApacheSpark:Spark 2.2.1 AWS上的EMR:EMR-5.12.1 内容,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有一个大数据帧,如下所示: val df = spark.read.option("basePath", "s3://some_bucket/").json("s3://some_bucket/group_id=*/") // Create view val df = spark.read.option("basePath", "s3://data_lake/").json("s3://data_lake/group_id=*/") df.createOrReplaceTempView("l

我有一个大数据帧,如下所示:

val df = spark.read.option("basePath", "s3://some_bucket/").json("s3://some_bucket/group_id=*/")
// 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/")
})
s3://some\u bucket
上有~1TB的JSON文件,它包括5000个
group\u id
分区。 我想使用SparkSQL执行转换,每个
group\u id
都不同

火花代码如下所示:

val df = spark.read.option("basePath", "s3://some_bucket/").json("s3://some_bucket/group_id=*/")
// 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的平行化无关

我真的很想在
scala.collection.Seq
中使用类似于
groupBy
的东西

这不是正确的火花代码:

df.groupBy(groupId).foreach((groupId, parDF) => {
  parDF.createOrReplaceTempView("lakeView")
  val convertedDF: DataFrame = spark.sql(queryByGroupId)
  convertedDF.write.save("s3://another_bucket")
})
1) 首先,如果您的数据已存储在每个组id的文件中,则没有理由将其混淆,然后使用Spark按id分组。 只为每个组id加载相关文件更简单、更高效

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

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

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

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

val parallelism = 10
val executor = Executors.newFixedThreadPool(parallelism)
val ec: ExecutionContext = ExecutionContext.fromExecutor(executor)
val tasks: Seq[String] = ???
val results: Seq[Future[Int]] = tasks.map(query => {
  Future{
    //spark stuff here
    0
  }(ec)
})
val allDone: Future[Seq[Int]] = Future.sequence(results)
//wait for results
Await.result(allDone, scala.concurrent.duration.Duration.Inf)
executor.shutdown //otherwise jvm will probably not exit 
1) 首先,如果您的数据已存储在每个组id的文件中,则没有理由将其混淆,然后使用Spark按id分组。 只为每个组id加载相关文件更简单、更高效

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

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

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

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

val parallelism = 10
val executor = Executors.newFixedThreadPool(parallelism)
val ec: ExecutionContext = ExecutionContext.fromExecutor(executor)
val tasks: Seq[String] = ???
val results: Seq[Future[Int]] = tasks.map(query => {
  Future{
    //spark stuff here
    0
  }(ec)
})
val allDone: Future[Seq[Int]] = Future.sequence(results)
//wait for results
Await.result(allDone, scala.concurrent.duration.Duration.Inf)
executor.shutdown //otherwise jvm will probably not exit 

很好的例子。如果我将其作为一个实用函数,它接受一个查询数组,并在将来使用sqlContext.sql(查询)提交,那么我如何将生成的DF数组作为一个数据帧数组返回?@Krishas不确定
DataFrame
s数组是您真正想要的<代码>数据帧不是计算的结果,只是描述。无论如何,我认为这是离题的,在注释中粘贴代码示例并不方便。如果您愿意,您可以创建一个单独的问题。我只想将数据帧返回给调用者。我知道这是离题的,不管怎样,它是可行的吗?@Krishas如果你只想返回一些数据帧而不实际计算它们,你很可能不会从并行性中获得任何提升。但这当然是可行的。在这种情况下(我也是),DF是查询输出,我们可以将其视为计算输出?为什么我不能在这里提高并行性?无论如何,每个查询都是并行运行的。。!!!很好的例子。如果我将其作为一个实用函数,它接受一个查询数组,并在将来使用sqlContext.sql(查询)提交,那么我如何将生成的DF数组作为一个数据帧数组返回?@Krishas不确定
DataFrame
s数组是您真正想要的<代码>数据帧不是计算的结果,只是描述。无论如何,我认为这是离题的,在注释中粘贴代码示例并不方便。如果您愿意,您可以创建一个单独的问题。我只想将数据帧返回给调用者。我知道这是离题的,不管怎样,它是可行的吗?@Krishas如果你只想返回一些数据帧而不实际计算它们,你很可能不会从并行性中获得任何提升。但这当然是可行的。在这种情况下(我也是),DF是查询输出,我们可以将其视为计算输出?为什么我不能在这里提高并行性?无论如何,每个查询都是并行运行的。。!!!