具有转义字段名称的 Scala 案例 class 在 Spark Catalyst 代码生成期间抛出错误
Scala case class with escaped field name throws error during Spark Catalyst code generation
我有一个案例 class 带有转义的字段名称,例如:
case class Buyer(`52_week`: String, `26_week`: String,... other fields)
然后我创建这个 class 的一个实例并像这样传递给 Spark DataFrame:
val expected = spark.createDataFrame(sc.parallelize(List(buyer1, buyer2)))
当我尝试保存它时:
expected.write.mode(SaveMode.Append).format("hive").partitionBy("load_date").saveAsTable(tableName)
我得到以下异常:
Caused by: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 476, Column 15: failed to compile: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 476, Column 15: Expression "funcResult15 = value65" is not a type
第 476 行是:
/* 475 */ Object funcResult15 = null;
/* 476 */ funcResult15 = value65.52_week();
看来我需要以某种方式告诉 Catalyst codegen 转义这些字段。
有没有办法解决这个问题,或者至少有一些解决方法?
我正在使用 Apache Spark 2.2.0。
我建议你做一个不同的case class
,用一个构造函数从旧的构造函数构建一个对象:
case class BuyerRenamed(week_52: String, week_26: String,... other fields)
object BuyerRenamed {
def apply(buyer: Buyer): BuyerRenamed = {
BuyerRenamed(buyer.`52_week`, buyer.`26_week`, ...)
}
}
然后将新案例 class 与数据框一起使用,这将解决 Catalyst 的问题,因为字段将被命名为 value65.week_52()
,这是对方法的适当命名。
也许您会想要添加隐式转换以使代码更简洁。
在很长的运行中,我建议您重构现有代码以摆脱这种命名,它可能会导致各种突发错误,尤其是当您以某种方式连接到自动代码生成时。
我所做的是将 Buyer class 转换为元组,并明确说明要使用的列名。
换句话说,我通过选择不同的路径来绕过代码生成。
代码片段如下所示:
val expected = spark.createDataFrame(sc.parallelize(List(buyer1, buyer2).map(b => Brand.unapply(b).get))).toDF(extractFieldNames[Buyer]:_*)
其中 extractFieldNames 是:
def extractFieldNames[T<:Product](implicit m: Manifest[T]): Array[String] =
m.erasure.getDeclaredFields.map(_.getName)
我有一个案例 class 带有转义的字段名称,例如:
case class Buyer(`52_week`: String, `26_week`: String,... other fields)
然后我创建这个 class 的一个实例并像这样传递给 Spark DataFrame:
val expected = spark.createDataFrame(sc.parallelize(List(buyer1, buyer2)))
当我尝试保存它时:
expected.write.mode(SaveMode.Append).format("hive").partitionBy("load_date").saveAsTable(tableName)
我得到以下异常:
Caused by: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 476, Column 15: failed to compile: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 476, Column 15: Expression "funcResult15 = value65" is not a type
第 476 行是:
/* 475 */ Object funcResult15 = null;
/* 476 */ funcResult15 = value65.52_week();
看来我需要以某种方式告诉 Catalyst codegen 转义这些字段。
有没有办法解决这个问题,或者至少有一些解决方法?
我正在使用 Apache Spark 2.2.0。
我建议你做一个不同的case class
,用一个构造函数从旧的构造函数构建一个对象:
case class BuyerRenamed(week_52: String, week_26: String,... other fields)
object BuyerRenamed {
def apply(buyer: Buyer): BuyerRenamed = {
BuyerRenamed(buyer.`52_week`, buyer.`26_week`, ...)
}
}
然后将新案例 class 与数据框一起使用,这将解决 Catalyst 的问题,因为字段将被命名为 value65.week_52()
,这是对方法的适当命名。
也许您会想要添加隐式转换以使代码更简洁。
在很长的运行中,我建议您重构现有代码以摆脱这种命名,它可能会导致各种突发错误,尤其是当您以某种方式连接到自动代码生成时。
我所做的是将 Buyer class 转换为元组,并明确说明要使用的列名。
换句话说,我通过选择不同的路径来绕过代码生成。
代码片段如下所示:
val expected = spark.createDataFrame(sc.parallelize(List(buyer1, buyer2).map(b => Brand.unapply(b).get))).toDF(extractFieldNames[Buyer]:_*)
其中 extractFieldNames 是:
def extractFieldNames[T<:Product](implicit m: Manifest[T]): Array[String] =
m.erasure.getDeclaredFields.map(_.getName)