使用 Scala 编写标量 UDF¶
您可以用 Scala 编写用户定义的标量函数 (UDF)。Scala 处理程序代码在调用 UDF 时执行。本主题介绍如何使用 Scala 编写处理程序并创建 UDF。
UDF 是用户定义的函数,会返回标量结果(即返回单个值而不是多行)。有关 UDFs 的更多一般信息,请参阅 用户定义函数概述。
创建 UDF 时,请执行以下操作:
使用在调用 UDF 时 Snowflake 将调用的方法编写一个 Scala 对象或类。
有关更多信息,请参阅 实施处理程序 (本主题内容)。
在 SQL 中使用 CREATE FUNCTION 命令创建 UDF,将对象或类指定为处理程序。创建 UDF 时,请指定:
UDF 输入参数的数据类型。
UDF 返回值的数据类型。
调用 UDF 时作为处理程序执行的代码。
编写处理程序所用的语言。
有关 CREATE FUNCTION 语法的更多信息,请参阅 使用 CREATE FUNCTION 创建 UDF。
您可以按照 UDF 中的说明调用 调用 UDF。
实施处理程序¶
使用处理程序方法实现对象或类,以将 UDF 实参值处理为 UDF 的返回值。
编写处理程序时,您可以执行以下操作:
使用要指定为处理程序的公共方法编写公共类。
在 UDF 中调用 SQL 时,这将是 Snowflake 调用的方法。
可以在同一对象或类中定义多个其他方法,然后将每个方法用作不同 UDF 的处理程序。例如,当您打算将编译后的处理程序代码保留在一个暂存区并从多个函数中引用它时,您可能要执行此操作。
有关暂存处理程序的更多信息,请参阅 将处理程序代码保持内联或保留在暂存区。
(可选)为 Snowflake 编写一个零实参构造函数,以便调用来初始化处理程序。
备注
请务必编写处理程序,使其在每个处理程序方法及其调用的方法中符合 Snowflake 施加的约束。有关这些约束的更多信息,请参阅 设计保持在 Snowflake 施加的约束范围内的处理程序。
处理程序示例¶
以下示例中的代码包括一个 MyHandler.echoVarchar
接收和返回字符串的处理程序方法。Snowflake 将接收的 UDF 值 ( VARCHAR ) 映射到处理程序方法的参数类型(字符串)。
CREATE OR REPLACE FUNCTION echo_varchar(x VARCHAR)
RETURNS VARCHAR
LANGUAGE SCALA
RUNTIME_VERSION = 2.12
HANDLER='MyHandler.echoVarchar'
AS
$$
class MyHandler {
def echoVarchar(x : String): String = {
return x
}
}
$$;
调用 UDF
SELECT echo_varchar('Hello');
初始化处理程序¶
您可以选择添加一个零实参构造函数来初始化处理程序。
如果构造函数抛出错误,则该错误将作为用户错误与异常消息一起抛出。
def this() = {
// Initialize here.
}
处理函数实参¶
要处理作为实参传递给 UDF 的数据,请实现一个公共方法,当在 SQL 代码中调用 UDF 时,Snowflake 将调用该方法。使用 CREATE FUNCTION 命令创建 UDF 时,将使用 HANDLER 子句将方法指定为处理程序。
声明处理程序方法时,您可以执行以下操作:
将处理程序方法声明为公共方法。
可以选择添加一个零实参构造函数来初始化处理程序。有关更多信息,请参阅 初始化处理程序 (本主题内容)。
如果打算以暂存处理程序的形式将类打包到 JAR 中,则可以声明多个处理程序方法,稍后使用 CREATE FUNCTION 语句的 HANDLER 子句将每个方法指定为处理程序。有关暂存处理程序的更多信息,请参阅 将处理程序代码保持内联或保留在暂存区。
指定处理程序方法的实参和返回类型,使其映射到 SQL 声明指定的 UDF 类型。
有关更多信息,请参阅 SQL-Scala 数据类型映射。
(可选)声明其他方法,以支持对处理程序方法进行的处理,例如从处理程序方法调用的方法。
以下示例中代码包含一个
handleStrings
处理程序方法,该方法调用非处理程序方法concatenate
来帮助处理作为实参接收的数组。CREATE OR REPLACE FUNCTION generate_greeting(greeting_words ARRAY) RETURNS VARCHAR LANGUAGE SCALA RUNTIME_VERSION = 2.12 HANDLER='StringHandler.handleStrings' AS $$ class StringHandler { def handleStrings(strings: Array[String]): String = { return concatenate(strings) } private def concatenate(strings: Array[String]): String = { var concatenated : String = "" for (newString <- strings) { concatenated = concatenated + " " + newString } return concatenated } } $$;
以下代码调用
generate_greeting
函数。SELECT generate_greeting(['Hello', 'world']);
以下是使用上述值调用
generate_greeting
的输出结果。Hello world
重载处理程序方法¶
可以重载同一类或对象中的处理程序方法,只要它们具有不同数量的参数即可。
对于 Scala UDFs,Snowflake 仅使用方法实参的 数量*(而不是它们的 *类型)来区分处理程序方法。基于数据类型进行解析是不切实际的,因为某些 SQL 数据类型可以映射到多个 Scala 或 Java 数据类型,因此可能映射到多个处理程序方法签名。
例如,如果两个 Scala 方法具有相同的名称、相同数量的实参,但是数据类型不同,则调用一个 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 时会发生错误。