我有UDF
处理JSON并返回每行的动态数据结果。在我的情况下,我需要这个来验证数据并返回验证数据。
每行的架构都很灵活。这意味着我无法为每种情况创建case class
(我的一些数据可以嵌套)。
我试图从我的UDF函数返回元组,但我也没有运气(因为我需要从列表转换为元组),而我没有找到一个优雅的解决方案。
我返回的数据类型有String
,Integer
,Double
,DateTime
,顺序不同。
我尝试在DataFrame上使用map
,但我的架构出现问题。
import spark.implicits._
def processData(row_type: String) = {
/*
completely random output here. Tuple/List/Array of
elements with a type Integer, String, Double, DateType.
*/
// pseudo-code starts here
if row_type == A
(1, "second", 3)
else
(1, "second", 3, 4)
}
val processDataUDF = udf((row_type: String) => processData(row_type))
val df = Seq((0, 1), (1, 2)).toDF("a", "b")
val df2 = df.select(processDataUDF($"a"))
df2.show(5)
df2.printSchema()
结果
+------------+
| UDF(a)|
+------------+
|[1,second,3]|
|[1,second,3]|
+------------+
我该如何处理这个问题?我们每row_type
有不同的处理结果。所有row_type
都是动态设置的。对于每个Schema
,我可以很好row_type
,但我不能使用不同的模式生成相同的UDF返回结果。
使用map
是唯一的方法吗?
答案 0 :(得分:5)
Spark Dataset
是一个列式数据结构,这里没有灵活架构的地方。 Schema必须是同类的(所有行必须具有相同的通用结构)并且已知(如果使用UDF,它必须返回定义良好的SQL类型)。
您可以通过以下方式获得一些灵活性:
nullable
。只有在没有类型冲突的情况下才可以执行此操作(如果Row
包含字段foo
,则始终使用相同的SQL类型表示它。)MapType
,ArrayType
)表示可变大小的字段。所有值和/或键必须属于同一类型。json4s
作为其依赖项,它为merging, diffing和querying JSON数据提供了一组工具。如果需要,它可用于应用相对复杂的转换。如果这不实用,我建议保留JSON字段"按原样#34;并仅按需解析它以提取特定值。您可以使用get_json_object
和显式类型转换。这允许测试不同的场景:
coalesce(Seq("$.bar", "$.foo.bar", "$.foobar.foo.bar")
.map(get_json_object($"json_col", _)): _*).cast(DoubleType)
不假设单一文档结构。
您可以使用二进制Encoders
(Encoders.kryo
,Encoders.java
)或RDD
API获得更多灵活性,这些API可用于存储联合类型(甚至{ {1}}),但如果您真的希望完全随机输出,则表明存在严重的设计或数据建模问题。即使您可以存储已分析的数据,也很难使用它。