带有转义字段名称的 Scala 案例类在 Spark Catalyst 代码生成期间引发错误

Posted

技术标签:

【中文标题】带有转义字段名称的 Scala 案例类在 Spark Catalyst 代码生成期间引发错误【英文标题】:Scala case class with escaped field name throws error during Spark Catalyst code generation 【发布时间】:2019-09-06 14:54:33 【问题描述】:

我有一个带有转义字段名称的案例类,例如:

case class Buyer(`52_week`: String, `26_week`: String,... other fields)

然后我创建这个类的一个实例并传递给 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。

【问题讨论】:

是什么让您在案例类中使用此类字段名称? @GoodDok 好吧,那段代码是在我之前编写的 你能以某种方式解决这个问题吗? 【参考方案1】:

我建议你创建一个不同的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`, ...)
  

然后使用带有数据框的新案例类,这将解决 Catalyst 的问题,因为字段将被命名为 value65.week_52(),这是对方法的适当命名。 也许您会想要添加隐式转换以使代码更清晰。

从长远来看,我建议您重构现有代码以摆脱这种命名,这可能会导致各种突发错误,尤其是当您以某种方式与自动代码生成相关时。

【讨论】:

我不确定我是否理解答案,因为我有一个名为 52_week 的列的 Hive 表,如果会有一个名为 week_52 的案例类,它们在插入 BuyerRenamed 期间将如何匹配? 好吧,如果 Hive 架构也稳定,则可以选择在保存字段之前重命名字段,例如 df.select(col("week_52").as("`52_week`"), other columns ...)【参考方案2】:

我所做的是将购买者类转换为元组,并明确说明要使用哪些列名。

换句话说,我通过选择不同的路径来绕过代码生成。

代码 sn-p 如下所示:

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)

【讨论】:

以上是关于带有转义字段名称的 Scala 案例类在 Spark Catalyst 代码生成期间引发错误的主要内容,如果未能解决你的问题,请参考以下文章

在编译时验证 Scala 案例类

如何自动将修改应用于Scala中案例类的所有/部分字段?

带有 casbah 的 scala 案例类。接受 objectid 参数作为字符串或 objectid

带有案例类的抽象类的scala circe编码器/解码器

Firebird字段名称转义

Oracle SQL - 字段名称中的转义与符号[重复]