一般 Scala UDF 处理程序编码准则¶
本主题介绍使用 Scala 编写处理程序代码的一般准则。有关特定于标量函数处理程序的信息,请参阅 使用 Scala 编写标量 UDF。
有关构建项目、打包代码和管理依赖项的建议,请参阅 Scala UDF 处理程序项目和打包。
最佳实践¶
编写独立于平台的代码。
避免使用假设特定 CPU 架构(例如 x86)的代码。
避免使用假定特定操作系统的代码。
如果需要执行初始化代码,但又不想将其包含在调用的方法中,可以将初始化代码放入处理程序类的一个辅助对象中。
使用内联处理程序时,请尽可能为 CREATE FUNCTION 或 CREATE PROCEDURE TARGET_PATH 参数指定一个值。这将促使 Snowflake 重用以前生成的处理程序代码输出,而不是每次调用都重新进行编译。有关更多信息,请参阅 使用内联处理程序。
编写处理程序¶
您可以使用用 Scala 编写的处理程序编写标量 UDF。
对于传递给 Scala UDF 的每一行,处理程序都会调用一次。不会为每一行创建新的类实例;Snowflake 可以多次调用同一实例的处理程序方法。
为了优化代码的执行,Snowflake 超时阈值在初始化处理程序类或对象所需的时间与执行其处理程序方法所需的时间之间有所不同。Snowflake 允许有更多时间初始化处理程序类或对象,前提是初始化可能需要更长的时间。这包括加载 UDF 的时间和调用处理程序方法的包含类的构造函数的时间(如果定义了构造函数)。
处理错误¶
您可以使用常见的异常处理技术处理异常,以捕获处理程序方法中的错误。
如果方法内部发生异常且未被方法捕获,则 Snowflake 会引发一个错误,其中包含异常的堆栈跟踪。
为了结束查询并产生 SQL 错误,可以显式抛出异常而不捕获它。例如:
if (x < 0) throw new IllegalArgumentException("x must be non-negative.")
调试时,可以在 SQL 错误消息文本中包含值。为此,请执行以下操作:
将整个 Scala 方法主体放在 try-catch 块中;
将实参值追加到捕获的错误消息中;并且
使用扩展消息抛出异常。
若要避免泄露敏感数据,请在将 JAR 文件部署到生产环境之前移除实参值。
选择数据类型¶
编写处理程序时,需要声明参数和返回数据类型(通过处理程序语言),以便与 UDF 的参数和返回数据类型(来自 SQL)很好地映射。
调用 UDF 时,Snowflake 会将 UDF 的实参从 SQL 参数类型转换为处理程序的参数类型。返回值时,Snowflake 会将返回值从处理程序的返回类型转换为 UDF 的返回类型。
Snowflake 根据支持的 SQL 类型和 Scala 类型之间的映射在类型间转换值。有关这些映射的详细信息,请参阅 SQL-Scala 数据类型映射。
在选择 Scala 变量的数据类型时,请考虑从 Snowflake 发送(和返回)数据的最大和最小可能值。
使用 CREATE FUNCTION
创建 UDF¶
您在 SQL 中使用 CREATE FUNCTION 命令创建 UDF,将您编写的代码指定为处理程序。有关命令参考,请参阅 CREATE FUNCTION。
CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
RETURNS <type>
LANGUAGE SCALA
[ IMPORTS = ( '<imports>' ) ]
RUNTIME_VERSION = 2.12
[ PACKAGES = ( '<package_name>' [, '<package_name>' . . .] ) ]
[ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
HANDLER = '<handler_class>.<handler_method>'
[ AS '<scala_code>' ]
要将您编写的处理程序代码与 UDF 关联,请在执行 CREATE FUNCTION 时执行以下操作:
将 LANGUAGE 设置为 SCALA。
如果处理程序类位于外部位置(例如,在暂存区上),则将 IMPORTS 子句值设置为该类的路径和名称。
将 RUNTIME_VERSION 设置为代码所需 Scala 运行时的版本。
将 PACKAGES 子句值设置为处理程序类所需的一个或多个包(如果有)的名称。
将 HANDLER 子句值设置为处理程序对象和方法的名称。
如果处理程序代码是使用 CREATE FUNCTION 内联指定,则
AS '<scala_code>'
子句是必需项。