- 可执行 UDFs 会启动外部程序或脚本 (Python、Bash 等) ,并通过 STDIN / STDOUT 以流式方式向其传输数据块。可用于在无需重新编译 ClickHouse 的情况下集成现有代码或工具。与进程内方案相比,它们的单次调用开销更高,因此更适合较重的逻辑,或需要不同运行时的场景。
- SQL UDFs 使用
CREATE FUNCTION通过纯 SQL 定义。它们会被内联/展开到查询计划中 (不存在进程边界) ,因此开销较低,非常适合复用表达式逻辑或简化复杂的计算列。 - Experimental WebAssembly UDFs 会在服务器进程内的沙箱中运行编译为 WebAssembly 的代码。与外部可执行程序相比,它们的单次调用开销更低;与原生扩展相比,又具备更好的隔离性,因此适合用可编译为 WASM 的语言 (如 C/C++/Rust) 编写自定义算法。
可执行用户自定义函数
此功能目前在 ClickHouse Cloud 中处于私有预览阶段。
如需开通,请通过 https://clickhouse.cloud/support 联系 ClickHouse 支持团队。
user_defined_executable_functions_config 参数指定。
函数配置包含以下设置:
| Parameter | Description | Required | Default Value |
|---|---|---|---|
name | 函数名称 | 是 | - |
command | 要执行的脚本名称;如果 execute_direct 为 false,则为要执行的命令 | 是 | - |
argument | 参数描述,包括参数的 type 以及可选的 name。每个参数都在单独的配置项中描述。如果参数名称是用户自定义函数序列化格式的一部分 (例如 Native 或 JSONEachRow) ,则必须指定名称 | 是 | c + argument_number |
format | 向命令传递参数时使用的 格式。命令输出也应使用相同的格式 | 是 | - |
return_type | 返回值的类型 | 是 | - |
return_name | 返回值名称。如果返回值名称是用户自定义函数序列化格式的一部分 (例如 Native 或 JSONEachRow) ,则必须指定返回值名称 | 可选 | result |
type | 可执行类型。如果 type 设置为 executable,则会启动单个命令;如果设置为 executable_pool,则会创建命令池 | 是 | - |
max_command_execution_time | 处理数据块的最大执行时间 (秒) 。此设置仅对 executable_pool 命令有效 | 可选 | 10 |
command_termination_timeout | 管道关闭后,命令应在多少秒内结束执行。超过该时间后,会向执行该命令的进程发送 SIGTERM | 可选 | 10 |
command_read_timeout | 从命令的 stdout 读取数据的超时时间 (毫秒) | 可选 | 10000 |
command_write_timeout | 向命令的 stdin 写入数据的超时时间 (毫秒) | 可选 | 10000 |
pool_size | 命令池大小 | 可选 | 16 |
send_chunk_header | 控制在向进程发送一块数据之前,是否先发送行数 | 可选 | false |
execute_direct | 如果 execute_direct = 1,则会在 user_scripts_path 指定的 user_scripts 文件夹中查找 command。可使用空白字符分隔符指定额外的脚本参数。例如:script_name arg1 arg2。如果 execute_direct = 0,则 command 会作为参数传递给 bin/sh -c | 可选 | 1 |
lifetime | 函数的重载间隔 (秒) 。如果设置为 0,则不会重新加载该函数 | 可选 | 0 |
deterministic | 函数是否为确定性的 (即对相同输入返回相同结果) | 可选 | false |
stderr_reaction | 如何处理命令的 stderr 输出。取值:none (忽略) 、log (立即记录所有 stderr) 、log_first (退出后记录前 4 KiB) 、log_last (退出后记录后 4 KiB) 、throw (一旦有任何 stderr 输出就立即抛出异常) 。当使用 log_first 或 log_last 且退出码非零时,stderr 内容会包含在异常消息中 | 可选 | log_last |
check_exit_code | 如果为 true,ClickHouse 会检查命令的退出码。非零退出码会导致异常 | 可选 | true |
STDIN 读取参数,并将结果输出到 STDOUT。命令必须以迭代方式处理参数。也就是说,处理完一批参数后,它必须等待下一批参数。
可执行用户自定义函数
示例
来自内联脚本的 UDF
test_function_sum,并将 execute_direct 指定为 0。
- XML
- YAML
文件
test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。/etc/clickhouse-server/test_function.xml
Query
Result
基于 Python 脚本的 UDF
STDIN 读取一个值,并将其作为字符串返回。
使用 XML 或 YAML 配置创建 test_function。
- XML
- YAML
文件
test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。/etc/clickhouse-server/test_function.xml
在
user_scripts 文件夹中创建脚本文件 test_function.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function.py) 。
Query
Result
从 STDIN 读取两个值,并将它们的和作为 JSON 对象返回
test_function_sum_json。
- XML
- YAML
文件
test_function.xml (默认路径设置下为 /etc/clickhouse-server/test_function.xml) 。/etc/clickhouse-server/test_function.xml
在
user_scripts 文件夹中创建脚本文件 test_function_sum_json.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function_sum_json.py) 。
Query
Result
在 command 设置中使用参数
command 设置中配置的常量参数 (仅适用于 executable 类型的用户自定义函数) 。
此外,还需要启用 execute_direct 选项,以避免 shell 参数展开漏洞。
- XML
- YAML
文件
test_function_parameter_python.xml (默认路径设置下为 /etc/clickhouse-server/test_function_parameter_python.xml) 。/etc/clickhouse-server/test_function_parameter_python.xml
在
user_scripts 文件夹中创建脚本文件 test_function_parameter_python.py (默认路径设置下为 /var/lib/clickhouse/user_scripts/test_function_parameter_python.py) 。
Query
Result
通过 shell 脚本创建 UDF
- XML
- YAML
文件
test_function_shell.xml (默认路径配置下为 /etc/clickhouse-server/test_function_shell.xml) 。/etc/clickhouse-server/test_function_shell.xml
在
user_scripts 文件夹中创建脚本文件 test_shell.sh (默认路径配置下为 /var/lib/clickhouse/user_scripts/test_shell.sh) 。
/var/lib/clickhouse/user_scripts/test_shell.sh
Query
Result
错误处理
参数表达式的求值
&&、|| 和 ?:。
在 ClickHouse 中,函数 (运算符) 的参数始终都会被求值。
这是因为系统会一次性对整块列数据进行求值,而不是逐行分别计算。
分布式查询处理中函数的执行
SELECT f(sum(g(x))) FROM distributed_table GROUP BY h(y), 中:
- 如果
distributed_table至少有两个分片,则函数 ‘g’ 和 ‘h’ 在远程服务器上执行,而函数 ‘f’ 在请求方服务器上执行。 - 如果
distributed_table只有一个分片,则 ‘f’、‘g’ 和 ‘h’ 这几个函数都会在该分片所在的服务器上执行。
hostName 函数,它返回其运行所在服务器的名称,以便在 SELECT 查询中按服务器进行 GROUP BY。
如果查询中的某个函数是在请求方服务器上执行的,但你需要它在远程服务器上执行,可以将其包裹在 ‘any’ 聚合函数中,或者将其添加到 GROUP BY 键中。