创建 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),并返回批量结果作为 Pandas 数组 (https://pandas.pydata.org/docs/reference/api/pandas.array.html) 或 Series (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.9

  • 3.10

  • 3.11

  • 3.12(预览版功能 – 现已面向所有账户开放。)

使用内联代码的 UDFs 与具有使用从暂存区上传的代码的 UDFs

可以通过以下任一方式指定 Python UDF 的代码:

  • 从暂存区上传:CREATE FUNCTION 语句指定现有 Python 源代码在 :doc:` 暂存区 </sql-reference/sql/create-stage>` 中的位置。

  • 内联:用于指定 Python 源代码的 CREATE FUNCTION 语句。

创建内联 Python UDF

对于内联 UDF,您可以将 Python 源代码作为 CREATE FUNCTION 语句的一部分提供。

例如,以下语句创建一个内联 Python UDF,为给定整数加一:

CREATE OR REPLACE FUNCTION addone(i INT)
  RETURNS INT
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.9'
  HANDLER = 'addone_py'
AS $$
def addone_py(i):
 return i+1
$$;
Copy

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

调用 UDF:

SELECT addone(10);
Copy

以下是输出:

+------------+
| 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
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.9'
  HANDLER = 'sleepy.snore'
  IMPORTS = ('@~/sleepy.py')
Copy

调用 UDF:

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

指定多个导入文件

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

CREATE OR REPLACE FUNCTION multiple_import_files(s STRING)
  RETURNS STRING
  LANGUAGE PYTHON
  RUNTIME_VERSION = 3.9
  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
语言: 中文