如何使用变换高阶函数?

时间:2018-12-13 12:12:35

标签: apache-spark apache-spark-sql

这与transform个高阶函数(https://issues.apache.org/jira/browse/SPARK-23908)有关。

有什么方法可以将它用作标准功能(在软件包org.apache.spark.sql.functions._中)?

我有一个字符串数组,我想将URI规范化应用于每个字符串。现在,我使用UDF做到了。我只是希望通过spark 2.4.0可以跳过UDF。

如我所见,它应该像selectExpr一样在df.selectExpr("transform(i, x -> x + 1)")中使用,但这是否仅意味着要与selectExpr一起使用?

以这种方式使用它是否可以为转换提供自定义功能?有什么方法可以实现,还是我应该使用良好的旧UDF?

1 个答案:

答案 0 :(得分:4)

  

无论如何,是否可以将其用作软件包org.apache.spark.sql.functions._中的标准函数??

目前,它仅适用于SQL表达式,尽管如果要返回Column,请使用expr

org.apache.spark.sql.functions._

expr("transform(i, x -> x + 1)"): Column
  

以这种方式使用它是否可以为转换提供自定义功能?

可以使用Scala UDF *:

spark.udf.register("f", (x: Int) => x + 1)

Seq((1, Seq(1, 2, 3))).toDF("id", "xs")
  .withColumn("xsinc", expr("transform(xs, x -> f(x))"))
  .show
+---+---------+---------+
| id|       xs|    xsinc|
+---+---------+---------+
|  1|[1, 2, 3]|[2, 3, 4]|
+---+---------+---------+

尽管与使用Seq的UDF相比,它似乎并没有提供任何真正的好处。


*似乎也已经部分支持Python UDF(可以识别udf,正确派生类型并分派调用),但是从2.4.0版开始,序列化机制似乎已损坏(所有记录都已被删除)。以None的形式传递给UDF:

from typing import Optional
from pyspark.sql.functions import expr

sc.version
'2.4.0'
def f(x: Optional[int]) -> Optional[int]:
    return x + 1 if x is not None else None

spark.udf.register('f', f, "integer")

df = (spark
    .createDataFrame([(1, [1, 2, 3])], ("id", "xs"))
    .withColumn("xsinc", expr("transform(xs, x -> f(x))")))

df.printSchema()
root
 |-- id: long (nullable = true)
 |-- xs: array (nullable = true)
 |    |-- element: long (containsNull = true)
 |-- xsinc: array (nullable = true)
 |    |-- element: integer (containsNull = true)
df.show()
+---+---------+-----+
| id|       xs|xsinc|
+---+---------+-----+
|  1|[1, 2, 3]| [,,]|
+---+---------+-----+

当然,这里没有提高性能的真正潜力-它调度到BasePythonRunner,因此开销应该与普通udf相同。

相关JIRA机票SPARK-27052 - Using PySpark udf in transform yields NULL values