scala ApacheSpark:从行中提取值的问题

gudnpqoy  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(182)

我对Spark中的Row类有很多问题。在我看来,Row类真的是一个设计很差的类。从Row中提取一个值应该不会比从Scala列表中提取一个值更困难;但在实践中,您必须知道列的确切类型才能提取它。您甚至不能将列转换为字符串;对于像Spark这样伟大的框架来说,这是多么荒谬?在现实世界中,在大多数情况下,您不知道列的确切类型,而且在许多情况下,您有数十或数百个列。下面是一个示例,向您展示我一直在获取的ClassCastExceptions。
有没有人有什么解决方案可以轻松地从行中提取值?

scala> val df = List((1,2),(3,4)).toDF("col1","col2")
df: org.apache.spark.sql.DataFrame = [col1: int, col2: int]

scala> df.first.getAs[String]("col1")
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
  ... 56 elided

scala> df.first.getAs[Int]("col1")
res12: Int = 1

scala> df.first.getInt(0)
res13: Int = 1

scala> df.first.getLong(0)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
  at scala.runtime.BoxesRunTime.unboxToLong(BoxesRunTime.java:105)
  at org.apache.spark.sql.Row$class.getLong(Row.scala:231)
  at org.apache.spark.sql.catalyst.expressions.GenericRow.getLong(rows.scala:165)
  ... 56 elided

scala> df.first.getFloat(0)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Float
  at scala.runtime.BoxesRunTime.unboxToFloat(BoxesRunTime.java:109)
  at org.apache.spark.sql.Row$class.getFloat(Row.scala:240)
  at org.apache.spark.sql.catalyst.expressions.GenericRow.getFloat(rows.scala:165)
  ... 56 elided

scala> df.first.getString(0)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
  at org.apache.spark.sql.Row$class.getString(Row.scala:255)
  at org.apache.spark.sql.catalyst.expressions.GenericRow.getString(rows.scala:165)
  ... 56 elided
mgdq6dx1

mgdq6dx11#

  • Spark是一个开源项目*。如果您不喜欢,可以修改接口。**不要因为得不到你想要的而消极看待*有很多其他选择。Spark已经尽可能地变得灵活了。

或者,您可以执行以下操作

df.first.get(0).toString
//res0: String = 1
df.first.get(0).toString.toLong
//res1: Long = 1
df.first.get(0).toString.toFloat
//res2: Float = 1.0

df.first.getAs[Int]("col1").toString
//res0: String = 1
df.first.getAs[Int]("col1").toLong
//res1: Long = 1
df.first.getAs[Int]("col1").toFloat
//res2: Float = 1.0

我再重复一遍,如果您对提供的API不满意,您可以随时扩展现有的API并实现您的API或创建您自己的API

o4tp2gmn

o4tp2gmn2#

它的存在是为了类型安全。如果您不确定列类型,只需将其视为字符串即可,在大多数情况下都适用。(以下是Java示例)

yourDataSet.foreach(row -> {
            log.info(row.getAs("yourColumnname").toString());
        });

相关问题