我正在通过Spark RDD进行映射,其功能非常昂贵(每行可能需要数十秒)。
该作业可能会花费太长时间,并且我需要中止该作业,以便为数据流中的其他作业让路。
但是,到目前为止计算出的结果对我仍然有用,所以我不想丢弃它们,尤其是因为它们可能已经花费了数小时来计算。
是否有办法在超时时提早退出转换,但保留到目前为止计算出的部分结果?
答案 0 :(得分:1)
通过从map
切换到相关的转换,至少有几种方法可以实现:
mapPartitions
mapPartitions
使我们可以访问每个分区上的迭代器,因此,如果超时到期,我们可以简单地假装其中没有任何项:
val data = sc.parallelize(1 to 100)
val timeout = 10000
val start = System.currentTimeMillis
data.repartition(10).mapPartitions { iter =>
if (System.currentTimeMillis - start > timeout) Iterator.empty
else iter.map(x => { Thread.sleep(500); x + 1 })
}.count
根据您的环境,您可能需要在此“火花壳”示例中调整超时,但是根据您运行转换的时间(相对于设置start
),它应该产生不同数量的结果。
请注意,分区的数量必须明显大于执行器核心的总数,否则所有分区将立即启动,并且没有要跳过的内容。因此,对于此示例,我们在开始mapPartitions
之前显式地对数据进行分区。您可能需要这样做,也可能不需要,这取决于数据的大小和预配置的内核数。
flatMap
更细粒度的方法是使用flatMap
,它使我们可以通过返回Option
的函数有条件地处理或跳过每一行(如果返回None
超时已过期);
// setup as before
data.flatMap{ x => if (System.currentTimeMillis - start > timeout) None
else Some({Thread.sleep(500); x + 1}) }.count
此方法不需要分区,但是即使在超时后仍会扫描所有剩余分区(但不会对任何行执行昂贵的处理)。