当前位置: 首页 > 面试题库 >

在SQLContext之外的Java中创建SparkSQL UDF

蔚和安
2023-03-14
问题内容

问题

我想在Java中创建一个用户定义函数,可以将其称为Apache
Spark运算符链中的Java方法。我在查找不需要UDF存在于SQL查询中的Java示例时遇到了麻烦。

版本号

  • Java 8
  • 斯卡拉2.10.6
  • 为Hadoop 2.6.0预先构建的Apache Spark 1.6.0

我尝试过的方法

我可以用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查询中。我感觉好像缺少了一些非常简单,基本的语法(可能是语法y),但是可能完全没有基础。

工作解决方案(由下面的零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()。


问题答案:

火花 > = 2.3

SPARK-22945(
在function对象中添加Java UDF API )添加了简化的udfAPI,类似于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")));

火花 <2.3

长话短说的functions.udf方法不是为Java互操作性而设计的。所有变体都需要TypeTags,虽然可以手动生成它们(我很确定我已经见过DanielDarabos展示了如何在SO上进行生成),但是您可能想避免这种情况。

如果出于某种原因要避免在Scala中编写UDF,最简单的方法是注册UDF
并按名称进行调用:

sqlContext.udf().register("udfUppercase",
  (String string) -> string.toUpperCase(), DataTypes.StringType);

df.select(callUDF("udfUppercase", col("name")));


 类似资料:
  • 问题内容: 我是Java新手。 我的文件如下所示: 在另一个Java文件中,我试图创建A对象调用 但是由于某种原因我得到了错误: 有人可以解释我该怎么做吗?我的意思是,我真的需要创建的实例,然后设置实例,然后将实例提供给方法,还是有另一种方法呢? 问题答案: 在您的示例中,您有一个内部类,该内部类始终与外部类的实例绑定。 如果您想要的只是嵌套类以提高可读性而不是实例关​​联的一种方式,那么您需要一

  • 我是Java新手。 我的文件看起来像这样: 在另一个java文件中,我试图创建一个调用 但由于某种原因,我得到了一个错误: 有人能解释一下我怎么做我想做的事吗?我的意思是,我真的需要创建的实例,然后将其设置为,然后将的实例赋给该方法吗,还是有其他方法可以做到这一点?

  • 我在Microsoft Windows7上使用的是。我想在一个变量中加载csv文件,以便稍后执行与SQL相关的操作,但无法这样做。我从这个链接引用了公认的答案,但没有用。我按照以下步骤创建对象和对象: 当我尝试时,它会说没有找到df。我尝试了从附加链接加载CSV的databricks解决方案。它下载软件包,但不加载csv文件。那么我怎样才能纠正我的问题呢?提前致谢:)

  • 我需要我的MediaPlayer对象作为类变量可见,而不是本地创建。 但是当我试图这样开始的时候- 这也以同样的错误失败- Logcat说- 进程:com。附录24.gg。relaaax,PID:24202 java。lang.RuntimeException:无法实例化活动

  • 问题内容: 我希望能够创建一个用Python初始化的类(在Python中),该类不接受新属性,但接受对现有属性的修改。我可以通过几种方法来做到这一点,例如,使用诸如 然后直接在内部进行编辑,但是我想知道是否存在“正确”的方法? 问题答案: 我不会直接使用,但是您可以添加一个函数来显式“冻结”实例:

  • 我的android项目叫做MyPlace。我想创建一个库(包)与comomTools类,生活在MyPlace目录之外;然而,每次我打开MyPlace项目,并创建一个新的模块,Android Studio创建一个目录内MyPlace称为通用工具。我想在外面创建这个公共工具目录,因为它在屏幕截图中显示,我更喜欢它不是一个Android项目。 我只是想能够从不同的Android应用程序从包中导入类。 我