创建 Python UDFs¶
本主题介绍如何创建和安装 Python UDF(用户定义函数)。
本主题内容:
编写 Python 代码¶
编写 Python 模块和函数¶
编写遵循以下规范的模块:
定义模块。模块是包含 Python 定义和语句的文件。
在模块内定义函数。
如果函数接受实参,则每个实参必须属于 :ref:` SQL-Python 类型映射表 <label-sql_python_data_type_mappings>` 的
Python Data Type
列中指定的数据类型。函数实参受位置(而不是名称)约束。传递给 UDF 的第一个实参是 Python 函数接收的第一个实参。
指定适当的返回值。由于 Python UDF 必须是标量函数,因此每次调用时它都必须返回一个值。返回值的类型必须属于 :ref:` SQL-Python 类型映射表 <label-sql_python_data_type_mappings>` 的
Python Data Type
列中指定的数据类型。返回值的类型必须与 CREATE FUNCTION 语句的RETURNS
子句中指定的 SQL 数据类型相兼容。模块可以包含多个函数。Snowflake 调用的函数可以调用同一模块或其他模块中的其他函数。
您的函数(以及您的函数调用的任何函数)必须符合 Snowflake 对 Python UDFs 施加的约束。
备注
通过矢量化 Python UDFs,您可以定义 Python 函数,该函数接收批量输入行作为 ` Pandas DataFrames <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html (https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html)>`_,并返回批量结果作为 ` Pandas 数组 <https://pandas.pydata.org/docs/reference/api/pandas.array.html (https://pandas.pydata.org/docs/reference/api/pandas.array.html)>`_ 或 ` Series <https://pandas.pydata.org/docs/reference/series.html (https://pandas.pydata.org/docs/reference/series.html)>`_。有关更多信息,请参阅 矢量化 Python UDFs。
在 Snowflake 中创建函数¶
您必须执行 CREATE FUNCTION 语句来指定:
用于 UDF 的名称。
在调用 Python UDF 时要调用的 Python 函数的名称。
UDF 的名称不需要匹配用 Python 编写的处理程序函数的名称。CREATE FUNCTION 语句中的 HANDLER 子句将 UDF 名称与 Python 函数相关联。
为 UDF 选择名称时,请参阅 命名和重载过程和 UDFs。
在 CREATE FUNCTION 语句的正文中,函数实参受位置(而不是名称)约束。CREATE FUNCTION 语句中声明的第一个实参是传递给 Python 函数的第一个实参。
有关实参的数据类型的信息,请参阅 SQL-Python 数据类型映射。
将 runtime_version
设置为代码所需 Python 运行时的版本。受支持的 Python 版本包括:
3.8
3.9
3.10
3.11
UDFs 使用内联代码与,UDFs 使用从暂存区上传的代码¶
可以通过以下任一方式指定 Python UDF 的代码:
从暂存区上传:CREATE FUNCTION 语句指定现有 Python 源代码在 :doc:` 暂存区 </sql-reference/sql/create-stage>` 中的位置。
内联:CREATE FUNCTION 语句指定 Python 源代码。
创建内联 Python UDF¶
对于内联 UDF,您可以将 Python 源代码作为 CREATE FUNCTION 语句的一部分提供。
例如,以下语句创建一个内联 Python UDF,为给定整数加一:
create or replace function addone(i int)
returns int
language python
runtime_version = '3.8'
handler = 'addone_py'
as
$$
def addone_py(i):
return i+1
$$;
Python 源代码在 AS
子句中指定。源代码可以放在单引号内,也可以放在一对美元符号 ($$
) 内。如果源代码包含嵌入的单引号,则使用双美元符号通常更容易。
调用 UDF:
select addone(10);
以下是输出:
+------------+
| ADDONE(10) |
|------------|
| 11 |
+------------+
Python 源代码可以包含多个模块和一个模块中的多个函数,因此 HANDLER
子句指定要调用的模块和函数。
内联 Python UDF 可以调用 IMPORTS
子句所含模块中的代码。
有关 CREATE FUNCTION 语句的语法的更多信息,请参阅 CREATE FUNCTION。
有关更多示例,请参阅 内联 Python UDF 示例。
使用从暂存区上传的代码创建 Python UDF¶
以下语句使用从 暂存区 上传的代码创建简单的 Python UDF。托管文件的暂存区必须可由 UDF 的 :emph:` 所有者 ` 读取。此外,ZIP 文件必须独立,并且不依赖要执行的任何其他安装脚本。
创建名为 sleepy.py
且包含源代码的 Python 文件:
def snore(n): # return a series of n snores
result = []
for a in range(n):
result.append("Zzz")
return result
启动 SnowSQL(CLI 客户端) 并使用命令 PUT,将文件从本地文件系统复制到名为 @~
的默认用户暂存区。( PUT
命令无法通过 Snowflake GUI 执行。)
put
file:///Users/Me/sleepy.py
@~/
auto_compress = false
overwrite = true
;
如果删除或重命名文件,则您无法再调用 UDF.如果需要更新文件,请在无法调用 UDF 时更新它。如果旧文件仍位于暂存区,则 PUT
命令应包含子句 OVERWRITE=TRUE
。
创建 UDF。处理程序指定模块和函数。
create or replace function dream(i int)
returns variant
language python
runtime_version = '3.8'
handler = 'sleepy.snore'
imports = ('@~/sleepy.py')
调用 UDF:
select dream(3);
+----------+
| DREAM(3) |
|----------|
| [ |
| "Zzz", |
| "Zzz", |
| "Zzz" |
| ] |
+----------+
指定多个导入文件¶
以下示例说明如何指定多个导入文件。
create or replace function multiple_import_files(s string)
returns string
language python
runtime_version=3.8
imports=('@python_udf_dep/bar/python_imports_a.zip', '@python_udf_dep/foo/python_imports_b.zip')
handler='compute'
as
$$
def compute(s):
return s
$$;
备注
指定的导入文件名必须不同。例如,以下指定无效:imports=('@python_udf_dep/bar/python_imports.zip', '@python_udf_dep/foo/python_imports.zip')
。
授予函数的权限¶
如果函数所有者以外的任何角色要调用函数,则所有者必须向角色授予适当的权限。
Python UDF 的 GRANT 语句与其他 UDFs(例如 JavaScript UDFs)的 GRANT 语句基本相同。
例如:
GRANT USAGE ON FUNCTION my_python_udf(number, number) TO my_role;