使用Spark的DataFrame时,需要用户定义函数(UDF)来映射列中的数据。 UDF要求显式指定参数类型。在我的情况下,我需要操作由对象数组组成的列,我不知道要使用什么类型。这是一个例子:
import sqlContext.implicits._
// Start with some data. Each row (here, there's only one row)
// is a topic and a bunch of subjects
val data = sqlContext.read.json(sc.parallelize(Seq(
"""
|{
| "topic" : "pets",
| "subjects" : [
| {"type" : "cat", "score" : 10},
| {"type" : "dog", "score" : 1}
| ]
|}
""")))
使用内置org.apache.spark.sql.functions
对列中的数据执行基本操作相对简单
import org.apache.spark.sql.functions.size
data.select($"topic", size($"subjects")).show
+-----+--------------+
|topic|size(subjects)|
+-----+--------------+
| pets| 2|
+-----+--------------+
并且通常很容易编写自定义UDF来执行任意操作
import org.apache.spark.sql.functions.udf
val enhance = udf { topic : String => topic.toUpperCase() }
data.select(enhance($"topic"), size($"subjects")).show
+----------+--------------+
|UDF(topic)|size(subjects)|
+----------+--------------+
| PETS| 2|
+----------+--------------+
但是如果我想使用UDF来操纵"对象"中的对象数组怎么办?柱?我在UDF中使用什么类型的参数?例如,如果我想重新实现size函数,而不是使用spark提供的函数:
val my_size = udf { subjects: Array[Something] => subjects.size }
data.select($"topic", my_size($"subjects")).show
显然Array[Something]
不起作用......我应该使用哪种类型!?我应该完全抛弃Array[]
吗?四处寻找告诉我scala.collection.mutable.WrappedArray
可能与它有关,但仍然有我需要提供的另一种类型。
答案 0 :(得分:23)
您正在寻找的是data b;
set a end=last;
if index(lowcase(name), 'a') > 0 then
people + 1;
if last then output;
keep people;
end;
:
Seq[o.a.s.sql.Row]
<强>解释强>:
import org.apache.spark.sql.Row
val my_size = udf { subjects: Seq[Row] => subjects.size }
的{{1}}当前代表ArrayType
因此WrappedArray
无法正常工作,最好保持安全。Array
的本地(外部)类型为StructType
。不幸的是,这意味着对各个字段的访问不是类型安全的。备注强>:
在Spark&lt;中创建Row
2.3,传递给struct
的函数必须返回udf
类型(Product
或Tuple*
),而不是case class
。这是因为相应的Row
变体depend on Scala reflection:
将 n 参数的Scala闭包定义为用户定义的函数(UDF)。根据Scala闭包的签名自动推断数据类型。
在Spark&gt; = 2.3中,可以直接返回udf
,as long as the schema is provided。
Row
使用Scala闭包定义确定性用户定义函数(UDF)。对于此变体,调用者必须指定输出数据类型,并且没有自动输入类型强制。
参见例如How to create a Spark UDF in Java / Kotlin which returns a complex type?。