我想将配置单元中现有的所有UDTF转换为Scala函数,并从Spark SQL中使用它

我想将配置单元中现有的所有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代

谁能给我举个例子;分解是用scala编写的,它返回多行并将其用作SparkSQL中的UDF

表:表1

+------+----------+----------+
|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|
+--------------+