Scala 使用尾部递归函数时try/catch不起作用
我正在构建一个尾部递归函数,它读取多个hdfs路径并将所有路径合并到一个数据帧中。只要所有路径都存在,函数就可以正常工作,如果不存在,函数将失败,并且没有完成连接确实存在的路径的数据。为了解决这个问题,我尝试使用try/catch来处理错误,但没有成功 错误显示:无法优化@tailrec注释的方法循环:它包含一个不在尾部位置的递归调用 我的职能是:Scala 使用尾部递归函数时try/catch不起作用,scala,apache-spark,Scala,Apache Spark,我正在构建一个尾部递归函数,它读取多个hdfs路径并将所有路径合并到一个数据帧中。只要所有路径都存在,函数就可以正常工作,如果不存在,函数将失败,并且没有完成连接确实存在的路径的数据。为了解决这个问题,我尝试使用try/catch来处理错误,但没有成功 错误显示:无法优化@tailrec注释的方法循环:它包含一个不在尾部位置的递归调用 我的职能是: def getRangeData(toOdate: String, numMonths: Int, pathRoot: String, Column
def getRangeData(toOdate: String, numMonths: Int, pathRoot: String, ColumnsTable: List[String]): DataFrame = {
val dataFrameNull = spark.createDataFrame(spark.sparkContext.emptyRDD[Row],
StructType((ColumnsTable :+ "odate").map(columnName => StructField(columnName, StringType, true))))
val rangePeriod = getRangeDate(numMonths, toOdate)
@tailrec
def unionRangeData(rangePeriod: List[LocalDate], pathRoot: String, df: DataFrame = dataFrameNull): DataFrame = {
try {
if (rangePeriod.isEmpty) {
df
}
else {
val month = "%02d".format(rangePeriod.head.getMonthValue)
val year = rangePeriod.head.getYear
val odate = rangePeriod.head.toString
val path = s"${pathRoot}/partition_data_year_id=${year}/partition_data_month_id=${month}"
val columns = ColumnsTable.map(columnName => trim(col(columnName)).as(columnName))
val dfTemporal = spark.read.parquet(path).select(columns: _*).withColumn("odate", lit(odate).cast("date"))
unionRangeData(rangePeriod.tail, pathRoot, df.union(dfTemporal))
}
} catch {
case e: Exception =>
logger.error("path not exist")
dataFrameNull
}
}
unionRangeData(rangePeriod, pathRoot)
}
def getRangeDate(numMonths: Int, toOdate: String, listDate: List[LocalDate] = List()): List[LocalDate] = {
if (numMonths == 0) {
listDate
}
else {
getRangeDate(numMonths - 1, toOdate, LocalDate.parse(toOdate).plusMonths(1).minusMonths(numMonths) :: listDate)
}
}
首先,非常感谢您的帮助。我建议您完全从函数中删除
try-catch
构造,并在getRangeData
底部的调用站点使用它
或者,您也可以使用scala.util.Try
包装调用:Try(unionRangeData(rangePeriod,pathRoot))
,并使用其组合符之一执行日志记录或在错误情况下提供默认值
解释Scala编译器无法在try catch内执行尾部调用优化的相关帖子:
我建议您完全从函数中删除
try-catch
构造,并在getRangeData
底部的调用站点使用它
或者,您也可以使用scala.util.Try
包装调用:Try(unionRangeData(rangePeriod,pathRoot))
,并使用其组合符之一执行日志记录或在错误情况下提供默认值
解释Scala编译器无法在try catch内执行尾部调用优化的相关帖子:
在处理Spark数据集时,我真的不认为担心尾部重复有多大意义。这感觉更像是担心火车的轮胎压力。我不明白你的意思,解释一下你的selftail递归是一种通过递归函数调用避免不必要的堆栈累积的技术。大多数spark操作(transform)产生一个表示计算图的AST,它只是一个数据结构。然后,仅当执行消耗操作时,才对该计算图进行优化和计算。这种计算也发生在分布式环境中。这意味着尾部递归的整个概念实际上(不应该)与Spark应用程序无关,如果你曾经需要担心Spark应用程序中的尾部递归,那么你做的事情确实是错误的,就像在火车上安装轮胎,然后担心轮胎压力。在处理Spark数据集时,我认为担心尾部递归没有多大意义。这感觉更像是担心火车的轮胎压力。我不明白你的意思,解释一下你的selftail递归是一种通过递归函数调用避免不必要的堆栈累积的技术。大多数spark操作(transform)产生一个表示计算图的AST,它只是一个数据结构。然后,仅当执行消耗操作时,才对该计算图进行优化和计算。这种计算也发生在分布式环境中。这意味着尾部递归的整个概念实际上(不应该)与Spark应用程序无关,如果您需要担心Spark应用程序中的尾部递归,那么您所做的事情实际上是错误的,类似于在火车上安装轮胎,然后担心轮胎压力。