使用数据框架构的Spark map数据框

时间:2016-05-27 14:06:13

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

我有一个从JSON对象创建的数据帧。我可以查询这个数据帧并将其写入实木复合地板。

由于我推断出架构,我不一定知道数据帧中有什么。

有没有办法将列名称输出或使用自己的模式映射数据框?

var a = {"name":"ab\
ac", age:"112"};

我想做点什么

// The results of SQL queries are DataFrames and support all the normal  RDD operations.
// The columns of a row in the result can be accessed by field index:
df.map(t => "Name: " + t(0)).collect().foreach(println)

// or by field name:
df.map(t => "Name: " + t.getAs[String]("name")).collect().foreach(println)

// row.getValuesMap[T] retrieves multiple columns at once into a Map[String, T]
df.map(_.getValuesMap[Any](List("name", "age"))).collect().foreach(println)
// Map("name" -> "Justin", "age" -> 19)

不知道列的实际数量或名称。

2 个答案:

答案 0 :(得分:4)

嗯,你可以但结果却毫无用处:

val df = Seq(("Justin", 19, "red")).toDF("name", "age", "color")

def getValues(row: Row, names: Seq[String]) = names.map(
  name => name -> row.getAs[Any](name)
).toMap

val names = df.columns
df.rdd.map(getValues(_, names)).first

// scala.collection.immutable.Map[String,Any] = 
//   Map(name -> Justin, age -> 19, color -> red)

为了获得实际有用的东西,可以在SQL类型和Scala类型之间进行正确的映射。在简单的情况下并不难,但总的来说很难。例如,内置类型可用于表示任意struct。这可以通过一些元编程来完成,但可以说它不值得大惊小怪。

答案 1 :(得分:0)

您可以使用隐式编码器并在DataFrame本身上执行映射:

implicit class DataFrameEnhancer(df: DataFrame) extends Serializable {
    implicit val encoder = RowEncoder(df.schema)

    implicit def mapNameAndAge(): DataFrame = {
       df.map(row => (row.getAs[String]("name") -> row.getAs[Int]("age")))
    }
}

并按如下方式在您的数据框上调用它:

val df = Seq(("Justin", 19, "red")).toDF("name", "age", "color")
df.mapNameAndAge().first

那样,您不必将DataFrame转换为RDD(在某些情况下,您不想从磁盘上加载整个DF,只需加载某些列,但是RDD转换迫使您执行此操作另外,您使用编码器而不是Kryo(或其他Java SerDes),速度更快。

希望它会有所帮助:-)