Apache Spark mapPartition奇怪的行为(懒惰的评价?)

时间:2017-08-02 08:15:33

标签: scala apache-spark

我试图使用像这样的代码(在Scala中)在RDD上记录每个mapPartition操作的执行时间:

rdd.mapPartitions{partition =>
   val startTime = Calendar.getInstance().getTimeInMillis
   result = partition.map{element =>
      [...]
   }
   val endTime = Calendar.getInstance().getTimeInMillis
   logger.info("Partition time "+(startTime-endTime)+ "ms")
   result
}

问题是它在开始执行地图操作之前立即记录“分区时间”,因此我总是获得2 ms的时间。

我通过观察Spark Web UI注意到它,在日志文件中,关于执行时间的行在任务开始后立即出现,而不是按预期结束。

有人能够解释我为什么吗?在mapPartitions中,代码应该线性执行,否则我错了?

由于

此致 卢卡

1 个答案:

答案 0 :(得分:3)

partitions内的{p> mapPartitionsIterator[Row],并且在Scala中懒惰地评估Iterator(即,当使用迭代器时)。这与Spark的懒惰唤醒无关!

调用partitions.size将触发对映射的评估,但会使用Iterator(因为它只能迭代一次)。一个例子

val it = Iterator(1,2,3)
it.size // 3
it.isEmpty // true

您可以做的是将Iterator转换为非惰性集合类型:

rdd.mapPartitions{partition =>
   val startTime = Calendar.getInstance().getTimeInMillis
   result = partition.map{element =>
      [...]
   }.toVector // now the statements are evaluated
   val endTime = Calendar.getInstance().getTimeInMillis
   logger.info("Partition time "+(startTime-endTime)+ "ms")
   result.toIterator
}

编辑:请注意,您可以使用System.currentTimeMillis()(甚至是System.nanoTime())而不是Calendar