Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Cloud 中的用户自定义函数

用户自定义函数 (UDF) 允许用户将 ClickHouse 的功能扩展到其内置的一千多种函数之外。

在 ClickHouse Cloud 中,有多种方式可以创建和管理用户自定义函数:

  1. 使用 SQL
  2. 使用 UI 和你自己的代码 (Public Beta)
  3. 使用 Cloud API (Beta)
  4. 使用 Terraform (Beta)

SQL 用户自定义函数

可以使用 CREATE FUNCTION 语句,基于 lambda 表达式创建 SQL UDF。

在此示例中,我们将创建一个简单的可执行用户自定义函数 isBusinessHours。 该函数会检查某个时间戳是否处于正常营业时间内;如果是则返回 true,否则返回 false。

  1. 登录 Cloud Console 并打开 SQL 控制台
  2. 编写以下 SQL 查询以创建 isBusinessHours 函数:
CREATE FUNCTION isBusinessHours AS (ts) ->
toDayOfWeek(ts) BETWEEN 1 AND 5
AND toHour(ts) BETWEEN 9 AND 17;
  1. 运行以下内容,测试你刚创建的 UDF:
SELECT isBusinessHours('2026-03-20 10:00:00'::DateTime), isBusinessHours('2026-03-20 23:00:00'::DateTime);

你应该会看到如下结果:

1   0
  1. 您可以使用 DROP FUNCTION 命令删除刚刚创建的 UDF:
DROP FUNCTION isBusinessHours

这意味着:

  • 会话级设置 (通过 SET 语句设置) 不会传递到 UDF 的执行上下文中
  • 用户 profile 中的设置不会被 UDFs 继承
  • 查询级设置在 UDF 执行期间不生效

通过 UI 创建的用户自定义函数

Beta 版功能

ClickHouse Cloud 提供了可通过 UI 创建用户自定义函数的配置界面。

在本示例中,我们将创建与前文相同的简单可执行用户自定义函数 isBusinessHours,用于检查某个时间戳是否落在正常工作时间内。 此前我们是通过 SQL 创建它的,这次则改用 Python 创建,并通过 UI 进行配置。

创建 Python 文件

在本地新建一个 main.py 文件:

cat > main.py << 'EOF'
import sys
from datetime import datetime

for line in sys.stdin:
    ts = datetime.fromisoformat(line.strip())
    result = 1 if (0 <= ts.weekday() <= 4 and 9 <= ts.hour <= 17) else 0
    print(result)
    sys.stdout.flush()
EOF

如果你的 Python 脚本导入了第三方包,请在 requirements.txt 文件中列出这些依赖项,ClickHouse Cloud 会为你安装。你也可以选择直接将依赖项打包到 ZIP 中,但这样就必须同时包含适用于两种 CPU 架构的缓存包,因此使用 requirements.txt 更简单。例如:

requests>=2.28.0
numpy>=1.23.0

打包依赖项和本地文件

要包含依赖包以及其他本地文件 (例如 wheel 文件、配置文件或数据文件) ,请将它们放在与您的 main.pyrequirements.txt 相同的目录中。创建 ZIP 归档时,请包含所有文件:

zip is_business_hours.zip main.py requirements.txt

你可以在 Python 代码中使用 os.path.dirname(os.path.abspath(__file__)) 引用本地打包路径的基目录。它会返回 ZIP 归档中 main.py 所在目录的绝对路径,以便你访问其他一并打包的文件:

import os

# Get the base directory of the bundled files
base_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(base_dir, 'config.json')

在你需要执行以下操作时,这会很有用:

  • 访问随 UDF 一起打包的配置文件
  • 为自定义依赖加载 wheel 包
  • 引用其他脚本或数据文件

现在将该文件压缩为 ZIP 压缩包:

zip is_business_hours.zip main.py

通过 UI 创建 UDF

  1. 在 Cloud 控制台主页上,点击左下角菜单中的组织名称。
  2. 从菜单中选择用户自定义函数
  3. 在用户自定义函数页面中,点击设置 UDF。屏幕右侧会打开一个配置面板。
  4. 输入函数名称。本示例使用 isBusinessHours
  5. 选择函数类型,可选 Executable poolExecutable
    • Executable pool:系统会维护一个持久进程池,并从池中取出进程来处理读取请求。
    • Executable:脚本会在每次查询时运行。
  6. 本示例使用默认设置。有关完整的配置参数列表,请参见可执行用户自定义函数
  7. 点击浏览文件,上传在本教程开头创建的 .zip 文件。
  8. 添加一个新参数。本示例中,添加一个类型为 DateTime 的参数 timestamp
  9. 选择返回类型。本示例中,选择 Bool
  10. 点击创建 UDF。此时会显示一个对话框,展示当前构建状态。
    • 如果出现任何问题,状态将变为错误
    • 否则,状态会从构建中变为预配中。你的服务必须处于唤醒状态才能完成预配。如果服务处于空闲状态,请在服务名称旁的 UDF 详细信息 面板中点击唤醒服务
    • 完成后,状态将变为已部署

测试你的 UDF

  1. 点击页面左上角的 Settings - 返回到服务视图,返回 SQL 控制台主页
  2. 点击左侧菜单中的 SQL 控制台
  3. 输入以下查询:
SELECT isBusinessHours('2026-03-20 10:00:00'::DateTime), isBusinessHours('2026-03-20 23:00:00'::DateTime);

你应该会看到如下结果:

true    false

创建新版本

如需更改 UDF 的代码,请创建一个新版本。Edit 面板仅用于管理 UDF 分配给哪些服务;在此处上传文件不会替换已部署的代码。

  1. 在 Cloud Console 首页,点击左下角菜单中的组织名称。
  2. 在菜单中选择 用户自定义函数
  3. isBusinessHours UDF 的 操作 一栏中点击三点图标,然后点击 创建新版本
  4. 上传包含修改后代码的 ZIP 压缩包,或修改设置,然后点击 创建新版本

你已成功通过 UI 添加了第一个用户自定义函数,确认其可正常运行,并了解了在需要时如何创建新版本。

使用 Cloud API 管理 UDF

Beta 版功能

UI 中提供的所有功能也可通过 ClickHouse Cloud API 以编程方式使用。 UDF 端点可让您通过脚本管理 UDF 的完整生命周期:上传源代码归档文件、创建函数和版本、将其附加到服务,以及进行清理。

通过 API 创建和部署 UDF 的典型工作流如下:

  1. 创建上传 URL 以获取预签名的 application/zip 上传 URL,然后将 ZIP 归档文件上传至该 URL。每个上传 ID 只能用于一次创建 UDF 或创建版本的尝试;重试时请申请新的上传 URL。
  2. 从上传的归档文件创建 UDF,并指定函数名称、运行时、参数和返回类型。
  3. 将 UDF 附加到服务。如果省略版本,则会附加最新的就绪版本。服务必须处于运行状态;可先唤醒空闲服务。

完整端点列表如下:

端点 描述
创建 UDF 上传 URL 创建组织范围的预签名 application/zip 上传 URL
创建 UDF 从已上传的归档文件创建新的 UDF
列出 UDF 返回组织中每个 UDF 的最新版本
获取 UDF 返回某个 UDF 的最新版本
删除 UDF 删除 UDF 的所有版本,并将其从所有服务中分离
创建 UDF 版本 使用源代码归档文件创建版本,并启动 UDF 构建
列出 UDF 版本 返回 UDF 的所有版本
删除 UDF 版本 删除未附加到任何服务的 UDF 版本
将 UDF 附加到服务 将一个 UDF 版本附加到服务,必要时替换当前版本
列出 UDF 附加关系 返回 UDF 当前附加到各服务的情况
获取 UDF 附加关系 返回 UDF 当前附加到某个服务的情况
从服务中分离 UDF 将 UDF 从服务中分离

有关请求和响应 schema,请参阅 UDF API 参考文档

使用 Terraform 管理 UDF

Beta 版功能

官方 ClickHouse Terraform provider 提供了两个资源,可用于以基础设施即代码的方式管理 UDF:

  • clickhouse_udf 用于管理函数本身。它接收包含函数源代码的 ZIP 归档文件,并在归档文件的哈希发生变化时发布新版本,同时等待构建完成。
  • clickhouse_udf_attachment 用于将 UDF 版本附加到服务。一个服务在同一时间最多只能使用一个函数版本。您可以固定指定版本号,也可以引用 clickhouse_udf.<name>.version,以自动将服务升级到最新版本。

例如,要使用 Terraform 部署前文示例中的 isBusinessHours UDF:

resource "clickhouse_udf" "is_business_hours" {
  function_name = "isBusinessHours"
  runtime       = "python3.11"
  type          = "executable_pool"
  return_type   = "Bool"

  arguments = [
    { name = "timestamp", type = "DateTime" },
  ]

  source_archive_path = "${path.module}/is_business_hours.zip"
  source_archive_hash = filebase64sha256("${path.module}/is_business_hours.zip")
}

resource "clickhouse_udf_attachment" "production" {
  function_name = clickhouse_udf.is_business_hours.function_name
  service_id    = var.service_id
  version       = clickhouse_udf.is_business_hours.version
}

仅当版本处于就绪状态时,附加操作才能成功,且可能需要数分钟;空闲服务会自动唤醒。删除 clickhouse_udf 资源会移除该函数的所有版本,并将其从所有服务中分离。

Navigation