我想知道是否有办法知道Spark保存操作写入的行数。我知道在编写之前对RDD进行计数就足够了,但是我想知道是否有办法在没有这样做的情况下获得相同的信息。
谢谢你, 马可
答案 0 :(得分:8)
如果您真的想要,可以添加自定义侦听器并从outputMetrics
中提取已写入的行数。非常简单的示例可能如下所示:
import org.apache.spark.scheduler.{SparkListener, SparkListenerTaskEnd}
var recordsWrittenCount = 0L
sc.addSparkListener(new SparkListener() {
override def onTaskEnd(taskEnd: SparkListenerTaskEnd) {
synchronized {
recordsWrittenCount += taskEnd.taskMetrics.outputMetrics.recordsWritten
}
}
})
sc.parallelize(1 to 10, 2).saveAsTextFile("/tmp/foobar")
recordsWrittenCount
// Long = 10
但这部分API仅供内部使用。
答案 1 :(得分:7)
接受的答案更符合OP的具体需求(如各种评论所述),但这个答案适合大多数人。
最有效的方法是使用累加器:http://spark.apache.org/docs/latest/programming-guide.html#accumulators
val accum = sc.accumulator(0L)
data.map { x =>
accum += 1
x
}
.saveAsTextFile(path)
val count = accum.value
然后你可以将它包装在一个有用的皮条客中:
implicit class PimpedStringRDD(rdd: RDD[String]) {
def saveAsTextFileAndCount(p: String): Long = {
val accum = rdd.sparkContext.accumulator(0L)
rdd.map { x =>
accum += 1
x
}
.saveAsTextFile(p)
accum.value
}
}
所以你可以做到
val count = data.saveAsTextFileAndCount(path)
答案 2 :(得分:0)
如果你看一下
]
您会看到它与taskEnd.taskInfo.accumulables
中的AccumulableInfo
按顺序捆绑在一起。
ListBuffer
您可以清楚地看到输出行的数量位于listBuffer的第7个位置,因此获取正在写入的行的正确方法是
AccumulableInfo(1,Some(internal.metrics.executorDeserializeTime),Some(33),Some(33),true,true,None),
AccumulableInfo(2,Some(internal.metrics.executorDeserializeCpuTime),Some(32067956),Some(32067956),true,true,None), AccumulableInfo(3,Some(internal.metrics.executorRunTime),Some(325),Some(325),true,true,None),
AccumulableInfo(4,Some(internal.metrics.executorCpuTime),Some(320581946),Some(320581946),true,true,None),
AccumulableInfo(5,Some(internal.metrics.resultSize),Some(1459),Some(1459),true,true,None),
AccumulableInfo(7,Some(internal.metrics.resultSerializationTime),Some(1),Some(1),true,true,None),
AccumulableInfo(0,Some(number of output rows),Some(3),Some(3),true,true,Some(sql)
我们可以通过以下方式获取行(我刚刚修改了@ zero323的答案)
taskEnd.taskInfo.accumulables(6).value.get