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是查询输出,我们可以将其视为计算输出?为什么我不能在这里提高并行性?无论如何,每个查询都是并行运行的。。!!!