Apache Spark:从Row中提取值的问题

时间:2018-03-23 04:06:53

标签: scala apache-spark apache-spark-sql spark-dataframe apache-spark-dataset

我在Spark中的Row类遇到了很多问题。在我看来,Row类是一个真正设计糟糕的类。从一行中提取值比从Scala列表中提取值更加困难并不困难;但实际上,您必须知道列的确切类型才能将其提取出来。您甚至无法将列转换为String;对于像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 

2 个答案:

答案 0 :(得分:2)

Spark是一个开源项目如果您不喜欢,可以修改api 不要因为你没有得到你想要的东西而将其视为负面。有很多选择。 Spark已尽可能灵活。

或者您可以执行以下操作

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

{{1}}

我再说一次,如果您对提供的apis不满意,您可以随时扩展现有的api并实施您自己的api

答案 1 :(得分:0)

在那里是为了类型安全。如果您不确定列的类型,只需将其视为字符串,即可在大多数情况下使用。 (这是Java Exmaple)

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