问题
我想在Java中创建一个用户定义函数,可以在Apache Spark运算符链中作为Java方法调用。我无法找到不需要在SQL查询中存在UDF的Java示例。
版本
我尝试过的工作
我可以用Java成功创建UDF。但是,我不能使用它,除非它在SQL查询中:
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.types.DataTypes;
sqlContext.udf().register("udfUppercase",
(String string) -> string.toUpperCase(), DataTypes.StringType);
DataFrame oldDF = // a simple DataFrame with a "name" column
oldDF.registerTempTable("df");
DataFrame newDF = sqlContext.sql("SELECT udfUppercase(name) AS name_upper FROM df");
我被困的地方
我希望Java中的非SQL方法调用样式的UDF看起来像这样:
import static org.apache.spark.sql.functions.udf;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.UserDefinedFunction;
import org.apache.spark.sql.types.DataTypes;
UserDefinedFunction udfUppercase = udf(
(String string) -> string.toUpperCase(), DataTypes.StringType);
DataFrame oldDF = // a simple DataFrame with a "name" column
newDF = oldDF.withColumn("name_upper", udfUppercase(oldDF.col("name")));
编译这会导致以“UserDefinedFunction”开头的行上的编译器错误,所以很明显我尝试猜测正确的签名是错误的:
error: no suitable method found for udf((String st[...]ase(),DataType)
UserDefinedFunction udfUppercase = udf((String string) -> string.toUpperCase(), DataTypes.StringType);
method functions.<RT#1>udf(Function0<RT#1>,TypeTags.TypeTag<RT#1>) is not applicable
(cannot infer type-variable(s) RT#1
(argument mismatch; Function0 is not a functional interface
multiple non-overriding abstract methods found in interface Function0))
此错误将继续详细说明每个推断的udf()签名。
我需要什么
我需要修复Java代码,以便我可以定义和使用udfUppercase UDF而无需将其嵌入SQL查询中。我觉得我错过了一些非常简单,基本和可能语法的东西,但可能完全偏离基础。
工作解决方案(由下面的零323提供)
没有很好的方法来注册和使用Java UDF作为Java方法,但是可以使用callUDF()将在SQLContext中注册的UDF插入到运算符链中。
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.types.DataTypes;
sqlContext.udf().register("udfUppercase",
(String string) -> string.toUpperCase(), DataTypes.StringType);
DataFrame oldDF = // a simple DataFrame with a "name" column
newDF = oldDF.withColumn("name_upper", callUDF("udfUppercase", oldDF.col("name")));
另外,请务必使用callUDF()而不是使用不同方法签名的已弃用的callUdf()。
答案 0 :(得分:8)
Spark&gt; = 2.3
https://jsfiddle.net/rwqc9bje/(在函数对象中添加java UDF API )添加了简化的udf
API,类似于Scala和Python:
import static org.apache.spark.sql.functions.*;
import org.apache.spark.sql.expressions.UserDefinedFunction;
UserDefinedFunction udfUppercase = udf(
(String s) -> s.toUpperCase(), DataTypes.StringType
);
df.select(udfUppercase.apply(col("name")));
Spark&lt; 2.3 强>
长篇短functions.udf
方法不是为Java互操作性而设计的。所有变体都需要TypeTags
,虽然可以手动生成这些变体(我很确定我已经看到SPARK-22945显示如何在SO上执行此操作)这是您可能想要避免的。
如果由于某种原因你想避免在Scala中编写UDF,最简单的方法是注册UDF Daniel Darabos:
sqlContext.udf().register("udfUppercase",
(String string) -> string.toUpperCase(), DataTypes.StringType);
df.select(callUDF("udfUppercase", col("name")));