创建 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
$$;
Copy

Python 源代码在 AS 子句中指定。源代码可以放在单引号内,也可以放在一对美元符号 ($$) 内。如果源代码包含嵌入的单引号,则使用双美元符号通常更容易。

调用 UDF:

select addone(10);
Copy

以下是输出:

+------------+
| ADDONE(10) |
|------------|
|         11 |
+------------+
Copy

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
Copy

启动 SnowSQL(CLI 客户端) 并使用命令 PUT,将文件从本地文件系统复制到名为 @~ 的默认用户暂存区。( PUT 命令无法通过 Snowflake GUI 执行。)

put
file:///Users/Me/sleepy.py
@~/
auto_compress = false
overwrite = true
;
Copy

如果删除或重命名文件,则您无法再调用 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')
Copy

调用 UDF:

select dream(3);

+----------+
| DREAM(3) |
|----------|
| [        |
|   "Zzz", |
|   "Zzz", |
|   "Zzz"  |
| ]        |
+----------+
Copy

指定多个导入文件

以下示例说明如何指定多个导入文件。

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
$$;
Copy

备注

指定的导入文件名必须不同。例如,以下指定无效: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;
Copy
语言: 中文