【发布时间】:2020-09-29 08:05:26
【问题描述】:
我正在构建一个尾递归函数,它读取多个 hdfs 路径并将所有这些路径合并到一个数据帧中。只要所有路径都存在,该功能就可以完美运行,如果不存在,则该功能将失败并且不会完成连接确实存在的路径的数据。为了解决这个问题,我尝试使用 try/catch 处理错误,但没有成功。
错误说:无法优化@tailrec注解的方法循环:它包含一个不在尾部位置的递归调用
我的功能是:
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)
}
}
在此先感谢您的帮助。
【问题讨论】:
-
在处理 Spark 数据集时,我真的认为担心尾递归没有多大意义。感觉更像是担心火车的胎压。
-
我不明白你的意思,你自己解释一下
-
尾递归是一种通过递归函数调用避免不必要的堆栈堆积的技术。大多数 spark 操作(转换)会产生一个表示计算图的 AST,它只是一个数据结构。然后仅在执行消耗操作时优化和计算该计算图。这种计算也发生在分布式环境中。这意味着尾递归的整个概念与 Spark 应用程序并不真正(不应该)相关。
-
一般来说(在某些情况下可能会有例外),如果您需要担心 Spark 应用程序中的尾递归,那么您的做法非常错误,类似于在火车上装轮胎然后担心轮胎压力。
标签: scala apache-spark