Scala 如何在Spark中并行化RDD/数据帧创建?

Scala 如何在Spark中并行化RDD/数据帧创建?,scala,parallel-processing,apache-spark,apache-spark-sql,Scala,Parallel Processing,Apache Spark,Apache Spark Sql,假设我有一份星火般的工作,如下所示: def loadTable1() { val table1 = sqlContext.jsonFile(s"s3://textfiledirectory/") table1.cache().registerTempTable("table1") } def loadTable2() { val table2 = sqlContext.jsonFile(s"s3://testfiledirectory2/") table2.cache()

假设我有一份星火般的工作,如下所示:

def loadTable1() {
  val table1 = sqlContext.jsonFile(s"s3://textfiledirectory/")
  table1.cache().registerTempTable("table1")
}  

def loadTable2() {
  val table2 = sqlContext.jsonFile(s"s3://testfiledirectory2/")
  table2.cache().registerTempTable("table2")
} 


def loadAllTables() {
  loadTable1()
  loadTable2()
}

loadAllTables()

如何并行化此Spark作业,以便同时创建两个表?

您可以使用标准的scala线程机制来完成此操作。就我个人而言,我想用路径和表名列出一组对,然后在上面进行并行映射。您还可以查看未来线程或标准线程。

您不需要将其并行化。RDD/DF创建操作什么都不做。这些数据结构是惰性的,因此只有在您开始使用它们时才会进行任何实际计算。当Spark计算发生时,它将自动并行化(逐分区)。Spark将在执行者之间分配工作。因此,引入进一步的并行性通常不会带来任何好处。

使用未来

implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10))

def loadAllTables() {
  Future { loadTable1() }
  Future { loadTable2() }
}

这个答案不适用于运行在多个节点上的Spark。嗨,Paul,这确实适用,因为注册表只能在驱动程序中完成。不,它不适用。查看关于懒惰的另一个答案。我在另一个答案中添加了一条注释,解释说虽然RDD创建是完全懒惰的,但因为我们讨论的是数据帧(特别是json数据帧),所以开发并不是完全懒惰的。您可以通过尝试从一个不存在的文件创建一个json数据帧来验证这一点,并注意到它会立即失败,这与常规RDD不同,在常规RDD中,它是完全惰性的,并且在我们对它执行操作之前不会失败。Dataframes+lazyness与常规RDD有点不同。显然,在单独的线程中运行它不会给您带来什么好处。这个答案有点正确,但是,由于我们在Spark SQL领域,情况就有点不同了。数据帧创建和注册操作实际上涉及到一些工作,特别是在json或类似结构中,Spark SQL需要扫描一些行来确定模式,而不仅仅是从头部读取模式。如果我们查看Catalog.scala,我们可以看到注册一个表涉及到查找计划,这迫使进行一些分析。我们通过创建一个不存在的数据帧并看到它失败(这意味着评估不是完全懒惰)来验证这一点。感谢Holden的评论!我不使用数据帧,所以我不知道它们的创建过程。尽管如此,与处理相比,创建一定是非常便宜的——我认为并行化不会带来太多好处。一个有趣的用例是,如果这是perm表,而不是temp表,例如带有附加模式的拼花格式。在这种情况下,它一点也不懒惰,因为您可能会在ETL过程中具体化很多表。我正试着做那样的事。我明白了每个“loadtable”被并行化的意思,但是如果每个表都不是很大的,那么registerEmptable就不会创建很多worker,所以并行化了很多单独串行(或最小并行)的负载可以更好地利用资源。您已将此发布到
user@spark
邮件列表也是。如果有人想阅读讨论,主题是“在Spark中并行创建多个RDD/数据帧”。