如何将地图传递到spark

时间:2017-07-14 14:04:54

标签: sql scala apache-spark user-defined-functions

这是我的问题,我有Map[Array[String],String]的地图,我希望将其传递给UDF。

这是我的UDF:

def lookup(lookupMap:Map[Array[String],String]) = 
  udf((input:Array[String]) => lookupMap.lift(input))

这是我的Map变量:

val srdd = df.rdd.map { row => (
  Array(row.getString(1),row.getString(5),row.getString(8)).map(_.toString),  
  row.getString(7)
)}

以下是我如何调用该函数:

val combinedDF  = dftemp.withColumn("a",lookup(lookupMap))(Array($"b",$"c","d"))

我首先得到一个关于不可变数组的错误,所以我将我的数组更改为不可变类型,然后我收到有关类型不匹配的错误。我用Google搜索了一下,显然我不能直接将非列类型传递给UDF。有人可以帮忙吗?荣誉。

更新:所以我确实将所有内容转换为包装数组。这是我做的:

val srdd = df.rdd.map{row => (WrappedArray.make[String](Array(row.getString(1),row.getString(5),row.getString(8))),row.getString(7))}

val lookupMap = srdd.collectAsMap()


def lookup(lookupMap:Map[collection.mutable.WrappedArray[String],String]) = udf((input:collection.mutable.WrappedArray[String]) => lookupMap.lift(input))


val combinedDF  = dftemp.withColumn("a",lookup(lookupMap))(Array($"b",$"c",$"d"))

现在我遇到这样的错误:

  

必需:Map [scala.collection.mutable.WrappedArray [String],String]   -ksh:Map [scala.collection.mutable.WrappedArray [String],String]:找不到[没有这样的文件或目录]

我试着这样做:

val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*) 

然后我回到了列类型的错误。

2 个答案:

答案 0 :(得分:1)

首先,您必须传递Column作为UDF的参数;由于您希望此参数为数组,因此应使用array中的org.apache.spark.sql.functions函数,该函数将从一系列其他列创建数组列。所以UDF调用将是:

lookup(lookupMap)(array($"b",$"c",$"d"))

现在,由于数组列被反序列化为mutable.WrappedArray,为了使地图查找成功,您最好确保您的UDF使用的类型:

def lookup(lookupMap: Map[mutable.WrappedArray[String],String]) =
  udf((input: mutable.WrappedArray[String]) => lookupMap.lift(input))

总而言之:

import spark.implicits._
import org.apache.spark.sql.functions._

// Create an RDD[(mutable.WrappedArray[String], String)]:
val srdd = df.rdd.map { row: Row => (
  mutable.WrappedArray.make[String](Array(row.getString(1), row.getString(5), row.getString(8))), 
  row.getString(7)
)}

// collect it into a map (I assume this is what you're doing with srdd...)
val lookupMap: Map[mutable.WrappedArray[String], String] = srdd.collectAsMap()

def lookup(lookupMap: Map[mutable.WrappedArray[String],String]) =
  udf((input: mutable.WrappedArray[String]) => lookupMap.lift(input))

val combinedDF  = dftemp.withColumn("a",lookup(lookupMap)(array($"b",$"c",$"d")))

答案 1 :(得分:0)

Anna您的srdd / lookupmap代码的类型为org.apache.spark.rdd.RDD [(Array [String],String)]

val srdd = df.rdd.map { row => (
Array(row.getString(1),row.getString(5),row.getString(8)).map(_.toString),  
  row.getString(7)
)}

在查找方法中,您期望将Map作为参数

def lookup(lookupMap:Map[Array[String],String]) = 
udf((input:Array[String]) => lookupMap.lift(input))

这就是您遇到类型不匹配错误的原因。

首先将RDD [元组]中的srdd转换为RDD [Map],然后尝试将RDD转换为Map以解决此错误。

val srdd = df.rdd.map { row => Map(
Array(row.getString(1),row.getString(5),row.getString(8)).map(_.toString) ->
  row.getString(7)
)}