在Spark Scala中将行转换为映射

12

我有一个数据帧中的一行数据,我想将其转换为一个Map[String, Any],将列名映射到该列的值。

有没有简单的方法可以做到这一点?

我已经针对字符串值做过此操作,例如

def rowToMap(row:Row): Map[String, String] = {
row.schema.fieldNames.map(field => field -> row.getAs[String](field)).toMap
}

val myRowMap = rowToMap(myRow)

如果行中包含其他值,而不是像字符串那样特定的值,则代码会变得混乱,因为该行没有.get(field)方法。

有什么想法吗?


分享输入和预期输出格式 - Balaji Reddy
4个回答

21

您可以使用getValuesMap

val df = Seq((1, 2.0, "a")).toDF("A", "B", "C")    
val row = df.first

获取Map[String, Any]

row.getValuesMap[Any](row.schema.fieldNames)
// res19: Map[String,Any] = Map(A -> 1, B -> 2.0, C -> a)

或者,对于这种简单情况,您可以获得Map[String, AnyVal],因为值不是复杂对象

row.getValuesMap[AnyVal](row.schema.fieldNames)
// res20: Map[String,AnyVal] = Map(A -> 1, B -> 2.0, C -> a)

注意getValuesMap 返回的值类型可以被标记为任何类型,因此您不能依赖它来确定自己拥有哪些数据类型,而是需要从一开始就记住您拥有的类型。


1
只有行具有模式,才能实现此操作。这是因为您使用了DF。如果您仅传递没有模式的行,则可以将值提取到Seq中,然后将其与字段名称一起压缩到映射中。 - Schmitzi
错误:无法找到类型为Map [String,Any]的编码器 - Yin

0
假设您有一个包含以下列的数据框: [time(TimeStampType),col1(DoubleType),col2(DoubleType)] 您可以执行以下操作:
val modifiedDf = df.map{row => 
    val doubleObject = row.getValuesMap(Seq("col1","col2"))
    val timeObject = Map("time" -> row.getAs[TimeStamp]("time"))
    val map = doubleObject ++ timeObject
}

0
你可以将你的 dataframe 转换为 rdd,并使用简单的 map 函数和在 map 函数中使用 headernames 在 MAP 形成内部,最后使用 collect。
val fn = df.schema.fieldNames
val maps = df.rdd.map(row => fn.map(field => field -> row.getAs(field)).toMap).collect()

0

假设您有一行没有结构信息,而列标题为数组。

val rdd = sc.parallelize( Seq(Row("test1", "val1"), Row("test2", "val2"), Row("test3", "val3"), Row("test4", "val4")) )
rdd.collect.foreach(println)

val sparkFieldNames = Array("col1", "col2")

val mapRDD = rdd.map(
  r => sparkFieldNames.zip(r.toSeq).toMap
)

mapRDD.collect.foreach(println)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接