Spark将任务分配给多个执行者

时间:2019-01-08 20:15:54

标签: apache-spark

我希望并行运行一个SQL查询,并且能够控制8个查询的并行度。现在,我正在执行这段代码。 这个想法是创建8个分区,并允许执行者并行运行它们。

UPDATE TABLENAME 
SET CAST(CAST(COLUMNNAME AS VARCHAR(MAX)) AS XML).modify('insert attribute currency{"INR"} into (/employee/salary)[1]')

问题是8个查询是一个接一个地运行的。

我应该如何继续让查询运行8乘8?

1 个答案:

答案 0 :(得分:2)

完成时

val df = (1 to 8).toSeq.toDF.repartition(8)

这将不会创建8个分区,每个分区有1条记录。如果您检查此数据框(例如,参见https://stackoverflow.com/a/46032600/1138523),则会得到:

+----------------+-----------------+
|partition_number|number_of_records|
+----------------+-----------------+
|               0|                0|
|               1|                0|
|               2|                0|
|               3|                0|
|               4|                0|
|               5|                0|
|               6|                4|
|               7|                4|
+----------------+-----------------+

因此,您将只有2个非空的分区,因此最多具有2倍的并行度(我在这里问过:How does Round Robin partitioning in Spark work?

要制作大小相等的分区,最好使用

spark.sparkContext.parallelize((0 to 7), numSlices = 8)

代替

(1 to 8).toSeq.toDF.repartition(8).rdd

第一个选项为每个分区提供1条记录,第二个选项则不使用循环分区

请注意,当您执行x.foreach时,x将被使用(迭代器只能遍历一次),因此,如果返回x,则始终会得到一个空的迭代器。

因此您的最终代码应如下所示:

 spark.sparkContext.parallelize((0 to 7), numSlices = 8)
.mapPartitions(
  x => {
  val xL = x.toList  // convert to List
  assert(xL.size==1) // make sure partition has only 1 record

  val conn = createConnection()
    xL.foreach{
      s => { // expect the below query be run concurently
      execute(s"SELECT * FROM myTable WHERE col = ${s}")
      }
    }
  conn.close()
  xL.toIterator
  })
 .collect // trigger all queries

除了使用mapPartitions(这是惰性的)之外,您还可以使用foreachPartition(这是非惰性的)

由于每个分区只有1条记录,因此对分区进行迭代并没有真正的好处,您也可以只使用普通的foreach

 spark.sparkContext.parallelize((0 to 7), numSlices = 8)
.foreach( s=> {
  val conn = createConnection()
  execute(s"SELECT * FROM myTable WHERE col = ${s}")   
  conn.close()
})