【问题标题】:How to select columns that exist in case classes from DataFrame如何从 DataFrame 中选择案例类中存在的列
【发布时间】:2021-09-08 19:44:21
【问题描述】:

给定一个带有 "id", "first", "last", "year" 列的 spark DataFrame

val df=sc.parallelize(Seq(
  (1, "John", "Doe", 1986),
  (2, "Ive", "Fish", 1990),
  (4, "John", "Wayne", 1995)
)).toDF("id", "first", "last", "year")

和案例类

case class IdAndLastName(
id: Int,
last:String )

我只想选择 idlast 的 case 类中的列。换句话说,我想通过使用案例类来获得这个输出df.select("id","last")。我避免对属性进行硬编码。您能否帮助我如何以紧凑的方式实现这一目标。

【问题讨论】:

  • 所以...假设您没有进行硬编码,而是想出了一种从数据框中选择列的“通用”方式。现在,您将如何在不知道列名的情况下使用该数据框?
  • 这是后期开发和预生产。硬编码的值越少,产品的质量就越高。任何人都可以通过查看案例类轻松查看列名,因为您可以将其写为df.select(fieldnames.head, fieldnames.tail:_*).as[IdAndLastName]
  • idlastcase class IdAndLastName(id: Int, last:String) 中是否没有硬编码?仅当数据帧具有名为 idlast 的显式字段时,此案例类的此编码器 hack 才有效。这与以任何方式仅使用“id”和“last”列名一样硬编码。这看起来像是对编码指南的错误解释或过度概括,即“如果可能,不要对事物进行硬编码”。这里的“硬编码”不仅仅是指“字符串”,而是指紧密耦合两个不相关的东西,这可能会发生变化,因此可能需要对代码进行多次更改。
  • 我认为您只是在考虑上述示例的规模。案例类在函数和对象的许多地方都得到了使用,并且 1)如果有修订(添加/删除/重命名列),我们不想去编辑每个地方 2)你已经回答了“The仅当数据帧具有名为 id 和 last 的显式字段时,此案例类的编码器才起作用“我们希望确保数据的结构/模式在所有地方都相同,如果某些操作/工程师丢失/以不同方式使用这些属性,让它失败了。这就是我们想要的。
  • 3) 在处理数据集时编写测试用例非常有帮助。 4)使用硬编码值,您将不会在编译时捕获与架构相关的错误,但您会意识到运行时的错误,这可能代价高昂...

标签: scala dataframe apache-spark case-class


【解决方案1】:

您可以为案例类显式创建编码器(通常这会隐式发生here)。然后就可以从编码器中获取字段名,并在select语句中使用:

val fieldnames = Encoders.product[IdAndLastName].schema.fieldNames
df.select(fieldnames.head, fieldnames.tail:_*).show()

输出:

+---+-----+
| id| last|
+---+-----+
|  1|  Doe|
|  2| Fish|
|  4|Wayne|
+---+-----+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-13
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-08
    相关资源
    最近更新 更多