创建 Java UDF 处理程序¶
本主题介绍如何为用户定义函数 (UDF) 编写 Java 处理程序。当您编写 Java UDF 时,您可以为 Snowflake 编写 Java 代码以作为 UDF 逻辑执行。这个 Java 代码是 UDF 的处理程序。
使用 UDF 来部署 CREATE FUNCTION,为 UDF 命名,并在调用 UDF 时指定 Java 方法作为要使用的处理程序。有关使用 SQL 来创建 UDF 的更多信息,请参阅 创建 UDF。
有关示例代码的更多信息,请参阅 Java UDF 处理程序示例。
本主题内容:
用 Java 编写 UDF 处理程序¶
在编写 Java UDF 处理程序时,请遵循以下要求和准则。
将类定义为 Public。
在类内部,声明至少一个用作 UDF 处理程序的公共方法。
对于内联 UDF,仅声明一个处理程序方法。相反,如果打算将类打包到 JAR 作为暂存处理程序,则可以声明多个处理程序方法,稍后使用 HANDLER 语句的 CREATE FUNCTION 子句将每个方法指定为处理程序。
有关内联和暂存处理程序之间的区别的更多信息,请参阅 将处理程序代码保持内联或保留在暂存区。
如果需要,可以声明处理程序方法调用的其他方法。
对每个处理程序方法,使用以下要求和准则:
将处理程序方法声明为 Public,可以是静态的,也可以是非静态的。
如果方法是非静态的,则类还必须声明零实参构造函数或根本不声明构造函数。
Snowflake 在实例化类时不会将任何实参传递给构造函数。如果构造函数抛出错误,则该错误将作为用户错误与异常消息一起抛出。
指定适当的返回类型。
返回类型必须是 SQL-Java 类型映射表 的
Java Data Type
列中指定的数据类型之一。返回类型必须与 CREATE FUNCTION 语句中的 RETURNS 子句中指定的 SQL 数据类型相兼容。确保每个处理程序方法实参(如有)都是 SQL-Java 类型映射表 的
Java Data Type
列中指定的数据类型。选择 Java 变量的数据类型时,请考虑可以从 Snowflake 发送(并返回)的数据的最大和最小可能值。
如果过载给定的 Java 类中的方法,请记住,Snowflake 仅使用方法实参的*数量*来区分类中的处理程序方法,而不是使用它们的*类型*。基于数据类型进行解析是不切实际的,因为某些 SQL 数据类型可以映射到多个 Java 数据类型,因此可能映射到多个处理程序方法签名。
例如,如果类中的两个 Java 方法具有相同的名称、相同数量的实参和不同的数据类型,则调用使用其中一种方法作为处理程序的 UDF 会生成类似于以下内容的错误:
Cannot determine which implementation of handler "handler name" to invoke since there are multiple definitions with <number of args> arguments in function <user defined function name> with handler <class name>.<handler name>
如果仓库可用,则在创建 UDF 时检测到错误。否则,在调用 UDF 时会发生错误。
在每个处理程序方法及其调用的方法中遵守 Snowflake 对 Java UDFs 施加的约束。有关这些约束的更多信息,请参阅 设计保持在 Snowflake 施加的约束范围内的处理程序。
将依赖关系添加到类路径¶
当处理程序代码需要用到外部 JAR 文件中封装的类时,可以将这些依赖关系添加到处理程序可用的 Snowflake 托管类路径。下面介绍如何将 JAR 文件添加到对 Java UDF 处理程序可见的类路径。有关更多信息,请参阅 为代码提供依赖项。
整理文件¶
如果您计划编译 Java 代码以自行创建 JAR 文件,则可以按如下所示整理文件。此示例假定您计划使用 Java 的包机制。
developmentDirectory
packageDirectory
class_file1.java
class_file2.java
classDirectory
class_file1.class
class_file2.class
manifest_file.manifest(可选)
jar_file.jar
put_command.sql
developmentDirectory
此目录包含创建 Java UDF 所需的项目特定的文件。
packageDirectory
此目录包含要编译并纳入包中的 .java 文件。
class_file#.java
这些文件包含 UDF 的 Java 源代码。
class_file#.class
这些是通过编译 .java 文件创建的 .class 文件。
manifest_file.manifest
将 .class 文件(以及可选的依赖关系 JAR 文件)合并到 JAR 文件中时使用的可选清单文件。
jar_file.jar
JAR 文件包含 UDF 代码。
put_command.sql
编译 Java 代码并创建 JAR 文件¶
要创建包含编译后的 Java 代码的 JAR 文件,请执行以下操作:
使用 Javac 将 .java 文件编译为 .class 文件。
如果使用比 11.x 版本更新的编译器,则可以使用“--release”选项来指定目标版本为 11 版本。
将 .class 文件放入文件 JAR。可以将多个类文件(和其他 JAR 文件)打包到文件 JAR 中。
例如:
jar cf ./my_udf.jar MyClass.class
如果处理程序类位于包中,则清单文件是必需的,否则是可选的。以下示例使用清单文件:
jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
要构建包含所有依赖关系的 Jar 文件,您可以通过 maven-assembly-plugin 来使用 Maven 的
mvn package
命令。有关 maven-assembly-plugin 的更多信息,请参阅 Maven 使用页面 (https://maven.apache.org/plugins/maven-assembly-plugin/usage.html)。Snowflake 自动提供 标准 Java 库 (https://docs.oracle.com/en/java/javase/11/docs/api/index.html) (例如
java.util
)。如果代码调用这些库,则无需将它们纳入 JAR 文件中。在库中调用的方法必须遵循 Snowflake 施加的约束,该约束与 Java 方法的约束相同。有关这些约束的更多信息,请参阅 设计保持在 Snowflake 施加的约束范围内的处理程序。
将 JAR 文件复制到暂存区¶
为了使 Snowflake 从包含处理程序方法的 JAR 中读取,您需要将 JAR 复制到以下各类暂存区之一:
用户或命名的内部暂存区。
Snowflake 当前不支持通过 JAR 处理程序使用表暂存区来存储 UDF 文件。有关内部暂存区的更多信息,请参阅 为本地文件选择内部暂存区。
外部暂存区。
托管 JAR 文件的暂存区必须可由 :emph:` 的`所有者UDF读取。
通常,使用 JAR 命令将 PUT 上传到命名的内部暂存区。请注意,您不能通过 Snowflake PUT
执行 GUI 命令;您可以使用 SnowSQL 来执行 PUT
。有关将 .jar 文件复制到暂存区的示例 PUT
命令,请参阅 Java UDF 处理程序示例 部分。
有关创建暂存区的更多信息,请参阅 CREATE STAGE。
注意事项和最佳实践
如果删除或重命名该 JAR 文件,则无法再调用 UDF。
如果您需要更新 JAR 文件,则请执行以下操作:
在不调用 UDF 时更新它。
如果旧的 .jar 文件仍存在于暂存区,则
PUT
命令应包含子句OVERWRITE=TRUE
。
备注
执行有关 UDFs 的操作的用户必须具有已被分配操作所需权限的角色。有关更多信息,请参阅 向用户定义函数授予权限。