我在spark用的数据块中有一个简单的UDF。我不能使用println或log4j之类的东西,因为它将输出到执行中,我需要在驱动程序中使用它。我有一个非常系统的日志设置
var logMessage = ""
def log(msg: String){
logMessage += msg + "\n"
}
def writeLog(file: String){
println("start write")
println(logMessage)
println("end write")
}
def warning(msg: String){
log("*WARNING* " + msg)
}
val CleanText = (s: int) => {
log("I am in this UDF")
s+2
}
sqlContext.udf.register("CleanText", CleanText)
如何使它正常运行并登录到驱动程序?
答案 0 :(得分:2)
Apache Spark中与您尝试执行的最接近的机制是累加器。您可以在执行程序上累积日志行,并在驱动程序中访问结果:
// create a collection accumulator using the spark context:
val logLines: CollectionAccumulator[String] = sc.collectionAccumulator("log")
// log function adds a line to accumulator
def log(msg: String): Unit = logLines.add(msg)
// driver-side function can print the log using accumulator's *value*
def writeLog() {
import scala.collection.JavaConverters._
println("start write")
logLines.value.asScala.foreach(println)
println("end write")
}
val CleanText = udf((s: Int) => {
log(s"I am in this UDF, got: $s")
s+2
})
// use UDF in some transformation:
Seq(1, 2).toDF("a").select(CleanText($"a")).show()
writeLog()
// prints:
// start write
// I am in this UDF, got: 1
// I am in this UDF, got: 2
// end write
BUT :实际上不建议这样做,尤其是不用于记录目的。如果您记录每条记录,则该累加器最终会在OutOfMemoryError
上使驱动程序崩溃,或者使您的速度大大降低。
由于您正在使用Databricks,因此我将检查它们支持日志聚合的哪些选项,或者仅使用Spark UI来查看执行程序日志。
答案 1 :(得分:0)
您不能……除非您想发疯,并制作某种通过网络或类似方式发送日志的回退附加程序。
在评估数据框时,将在所有执行程序上运行UDF的代码。因此,您可能有2000台主机在运行它,并且每台主机都将记录到自己的位置。这就是Spark的工作方式。该驱动程序不是运行代码的驱动程序,因此无法登录。
您可以使用YARN日志聚合从执行程序中提取所有日志,以供以后分析。
您可能还可以通过一些工作向kafka流或类似的创意写入内容,然后在该流之后连续写入日志。