我想将配置单元中现有的所有UDTF转换为Scala函数,并从Spark SQL中使用它
谁能给我举个例子;分解是用scala编写的,它返回多行并将其用作SparkSQL中的UDF 表:表1我想将配置单元中现有的所有UDTF转换为Scala函数,并从Spark SQL中使用它,scala,hadoop,apache-spark,hive,apache-spark-sql,Scala,Hadoop,Apache Spark,Hive,Apache Spark Sql,谁能给我举个例子;分解是用scala编写的,它返回多行并将其用作SparkSQL中的UDF 表:表1 +------+----------+----------+ |userId|someString| varA| +------+----------+----------+ | 1| example1| [0, 2, 5]| | 2| example2|[1, 20, 5]| +------+----------+----------+ 我想创建以下Scala代
+------+----------+----------+
|userId|someString| varA|
+------+----------+----------+
| 1| example1| [0, 2, 5]|
| 2| example2|[1, 20, 5]|
+------+----------+----------+
我想创建以下Scala代码:
def exampleUDTF(var: Seq[Int]) = <Return Type???> {
// code to explode varA field ???
}
sqlContext.udf.register("exampleUDTF",exampleUDTF _)
sqlContext.sql("FROM table1 SELECT userId, someString, exampleUDTF(varA)").collect().foreach(println)
你不能用UDF来做这件事。UDF只能向数据帧添加一列。但是,有一个名为DataFrame.explode的函数,您可以改用它。要使用您的示例执行此操作,您可以执行以下操作:
import org.apache.spark.sql._
val df = Seq(
(1,"example1", Array(0,2,5)),
(2,"example2", Array(1,20,5))
).toDF("userId", "someString", "varA")
val explodedDf = df.explode($"varA"){
case Row(arr: Seq[Int]) => arr.toArray.map(a => Tuple1(a))
}.drop($"varA").withColumnRenamed("_1", "varA")
+------+----------+-----+
|userId|someString| varA|
+------+----------+-----+
| 1| example1| 0|
| 1| example1| 2|
| 1| example1| 5|
| 2| example2| 1|
| 2| example2| 20|
| 2| example2| 5|
+------+----------+-----+
请注意,explode将函数作为参数。因此,即使您不能创建一个UDF来做您想做的事情,您也可以创建一个函数来传递分解来做您想做的事情。像这样:
def exploder(row: Row) : Array[Tuple1[Int]] = {
row match { case Row(arr) => arr.toArray.map(v => Tuple1(v)) }
}
df.explode($"varA")(exploder)
这是您在重新创建UDTF方面获得的最佳结果。蜂巢表:
name id
["Subhajit Sen","Binoy Mondal","Shantanu Dutta"] 15
["Gobinathan SP","Harsh Gupta","Rahul Anand"] 16
创建scala函数:
def toUppername:Seq[String]=name.mapa=>a.toUpperCase.toSeq
将函数注册为UDF:
sqlContext.udf.registertoUpper,toUpper_
使用sqlContext调用UDF并将输出存储为DataFrame对象:
var df=sqlContext.sqlSELECT toUppername FROM namelist.toDFName
分解数据帧:
df.explodedfName{case org.apache.spark.sql.Rowarr:Seq[String]=>arr.toSeq.mapv=>Tuple1v}.dropdfName.withColumnRenamed_1,Name.show
结果:
+--------------+
| Name|
+--------------+
| SUBHAJIT SEN|
| BINOY MONDAL|
|SHANTANU DUTTA|
| GOBINATHAN SP|
| HARSH GUPTA|
| RAHUL ANAND|
+--------------+
这是关于explode的,但是我想用一种方法来构建我的自定义函数以用作UDTF。基本上,我的函数应该从表中输入一列复杂类型的Map、Struct或Array,并将单个条目拆分为单行对象,返回列表或行序列。我需要一个自定义的explode函数,以防我必须对每个序列执行操作,如:太好了,你想要什么。这不是它的工作原理。你要爆炸了。使用爆炸。或者不要。由你决定。在这里,我稍微编辑了一下,也许会更接近你想要的。我的新问题稍加修改:老实说@zero323,我一开始还以为这是重复的。但是看看我下面的修正答案——也许能够传递一个预定义的函数来分解,而不是匿名声明一个函数是有价值的。@DavidGriffin老实说,没有类型安全性,没有检查和非穷举的模式匹配,我不相信:特别是当分解是安全的并且不需要任何额外的操作时密码但是,既然OP发布了另一个问题,你的答案可能会涉及到这个问题,我们可以重新打开这个问题,关闭另一个WTF-这个家伙一遍又一遍地问同一个问题多少次?嘿,@zero323,我在下面编辑了我的答案。就类型安全性而言,我看不出我对explode的两种用法有什么不同。如果是,你能解释一下吗?@DavidGriffin尝试在例如df.withColumnvarA、$varA.castarray上执行它
+--------------+
| Name|
+--------------+
| SUBHAJIT SEN|
| BINOY MONDAL|
|SHANTANU DUTTA|
| GOBINATHAN SP|
| HARSH GUPTA|
| RAHUL ANAND|
+--------------+