我是Scala的新手,所以请原谅我可怜的笔迹。 我有一个函数func1,它接受两个字符串并返回一个字符串。 我也有一个具有2列a1和b1的数据框df1。我正在尝试使用来自df1的列(a1和b1)和作为功能func1的输出的新列c1创建一个新的数据框df2。我知道我需要使用UDF。我不知道如何创建可以接受2列的UDF,并将这两列作为参数传递给func1并返回输出字符串(列c1)。
这是我尝试过的一些事情-
def func1(str1:String, str2:String) : String = {
//code
return str3;
}
val df1= spark.sql("select * from emp")
.select("a1", "b1").cache()
val df2 = spark.sql("select * from df1")
.withColumn("c1", func1("a1","b1"))
.select("a1", "b1").cache()
但是我没有得到结果。请指教。提前致谢。
答案 0 :(得分:2)
您基本上有语法问题。
请记住,当您执行def func1(str1:String, str2:String) : String = ...
时func1是指Scala函数对象,而不是Spark表达式。
另一方面,.withColumn
期望将Spark表达式作为第二个参数。
因此,发生的情况是您对.withColumn("c1", func1("a1","b1"))
的调用向Spark发送了一个Scala function
对象,而Spark API期望使用“ Spark Expression”(例如,列或对列的操作,例如用户定义函数(UDF)。
幸运的是,通常来说,通过调用Spark的udf
方法来包装Scala函数,将其转换为Spark UDF很容易。
因此,一个可行的示例可以这样发出:
// A sample dataframe
val dataframe = Seq(("a", "b"), ("c", "d")).toDF("columnA", "columnB")
// An example scala function that actually does something (string concat)
def concat(first: String, second: String) = first+second
// A conversion from scala function to spark UDF :
val concatUDF = udf((first: String, second: String) => concat(first, second))
// An sample execution of the UDF
// note the $ sign, which is short for indicating a column name
dataframe.withColumn("concat", concatUDF($"columnA", $"columnB")).show
+-------+-------+------+
|columnA|columnB|concat|
+-------+-------+------+
| a| b| ab|
| c| d| cd|
+-------+-------+------+
从那里开始,应该很容易适应您的精确函数及其参数。
答案 1 :(得分:1)
这是您要怎么做
scala> val df = Seq(("John","26"),("Bob","31")).toDF("a1","b1")
df: org.apache.spark.sql.DataFrame = [a1: string, b1: string]
scala> df.createOrReplaceTempView("emp")
scala> :paste
// Entering paste mode (ctrl-D to finish)
def func1(str1:String, str2:String) : String = {
val str3 = s" ${str1} is ${str2} years old"
return str3;
}
// Exiting paste mode, now interpreting.
func1: (str1: String, str2: String)String
scala> val my_udf_func1 = udf( func1(_:String,_:String):String )
my_udf_func1: org.apache.spark.sql.expressions.UserDefinedFunction = UserDefinedFunction(<function2>,StringType,Some(List(StringType, StringType)))
scala> spark.sql("select * from emp").withColumn("c1", my_udf_func1($"a1",$"b1")).show(false)
2019-01-14 21:08:30 WARN ObjectStore:568 - Failed to get database global_temp, returning NoSuchObjectException
+----+---+---------------------+
|a1 |b1 |c1 |
+----+---+---------------------+
|John|26 | John is 26 years old|
|Bob |31 | Bob is 31 years old |
+----+---+---------------------+
scala>
您需要更正两个地方。
定义常规函数后,您需要将其在udf()中注册为
val my_udf_func1 = udf( func1(_:String,_:String):String )
在调用udf时,您应该使用$"a1"
语法,而不仅仅是"a1"