玩转 Databend UDF
引言
Databend 作为新一代云原生数据仓库,提供了六百多个内置函数,满足了大部分用户的需求。然而,随着业务的增长,需求也变的日新月异,内置的函数可能无法服务用户变化的需求。在这种场景下, Databend 提供了多种用户自定义函数(UDF)实现方式,满足不同场景下的数据处理需求。
本文将深入探讨三种 UDF 形态:Lambda UDF、UDF Script 和 External UDF Server,并通过具体的案例展示它们的实现方式,最后进行性能对比分析。
Lambda UDF:纯 SQL 定义的函数语法糖
Lambda UDF 是 Databend 中最简单的 UDF 形式,完全通过 SQL 语句定义和执行表达式,适合简单的数据转换和计算。
我们可以在 SQL 中定义一个闭包函数,然后进行调用。
Lambda UDF 示例:
🐳 root@default:) CREATE FUNCTION plus_3 AS (a,b,c) -> a + b + c; 🐳 root@default:) select plus_3(1,2,3); ╭─────────────────╮ │ plus_3(1, 2, 3) │ │ UInt8 │ ├─────────────────┤ │ 6 │ ╰─────────────────╯ 🐳 root@default:) CREATE FUNCTION age AS (d) -> date_diff(year, d, now()); 🐳 root@default:) select age('1992-01-01'::Date); ╭─────────────────────────╮ │ age('1992-01-01'::DATE) │ │ Int64 │ ├─────────────────────────┤ │ 33 │ ╰─────────────────────────╯
它的特点:
- 纯 SQL 实现,无需外部语言支持
- 无法支持递归调用
- 执行性能受表达式定义影响
UDF Script:多语言扩展能力
Databend 引擎中支持内嵌的多语言执行器, 可以执行通过 Python、JavaScript 和 WASM 编写 UDF Script,适合复杂业务逻辑实现。
- Python UDF
Databend 使用了 pyo3 引擎来执行 Python script, 我们可以通过如下方式定义一个简单的 Python UDF。
CREATE FUNCTION fib_python ( Int32 ) RETURNS Int32 LANGUAGE python HANDLER = 'fib' AS $$ def fib(n): a, b = 0, 1 for _ in range(n): a, b = b, a + b return a $$; select plus_3(1,2,3); ╭─────────────────╮ │ plus_3(1, 2, 3) │ │ UInt8 │ ├─────────────────┤ │ 6 │ ╰─────────────────╯
- Javascript UDF
Databend 使用了 rquickjs 引擎来执行 Javascript, 我们可以通过如下方式定义一个简单的 Javascript UDF。
CREATE OR REPLACE FUNCTION fib_js ( Int32 ) RETURNS Int32 LANGUAGE JAVASCRIPT HANDLER = 'fib' AS $$ export function fib(n) { let a = 0, b = 1; for (let i = 0; i < n; i++) { [a, b] = [b, a + b]; } return a } $$; 🐳 root@default:) select fib_js(10); ╭─────────────────╮ │ fib_js(10) │ │ Nullable(Int32) │ ├─────────────────┤ │ 55 │ ╰─────────────────╯
特点:
-
支持完整语言特性,实现复杂逻辑
-
Python UDF 特别适合数据科学和AI集成
-
JavaScript UDF 适合轻量级数据处理,同时兼顾沙箱安全性
-
UDF script 属于 Databend 企业特性
-
WASM UDF 你可以使用 rust 代码来实现 UDF, 然后编译到 Wasm target 中,示例教程。
- 创建一个项目,Cargo.toml 包含 arrow-udf 依赖
[package] name = "arrow-udf-example" version = "0.1.0" [lib] crate-type = ["cdylib"] [dependencies] arrow-udf = "0.8"
- 使用
#[function]
宏来定义你的函数
use arrow_udf::function; #[function("fib(int) -> int")] fn fib(n: i32) -> i32 { let (mut a, mut b) = (0, 1); for _ in 0..n { let c = a + b; a = b; b = c; } a }
然后编译到 wasm32-wasip1
cargo build --release --target wasm32-wasip1
将生成的 result.wasm 文件传到 databend stage 中,并定义 wasm udf 函数
🐳 root@default:) create stage s_udf; 🐳 root@default:) put fs:///tmp/arrow_udf_example.wasm @s_udf/; ╭─────────────────────────────────────────────────╮ │ file │ status │ size │ │ String │ String │ UInt64 │ ├─────────────────────────────┼─────────┼─────────┤ │ /tmp/arrow_udf_example.wasm │ SUCCESS │ 1279392 │ ╰─────────────────────────────────────────────────╯ 🐳 root@default:) CREATE OR REPLACE FUNCTION fib_wasm (INT) RETURNS INT LANGUAGE wasm HANDLER = 'fib' AS $$@s_udf/arrow_udf_example.wasm$$; 🐳 root@default:) select fib_wasm(10::Int32); ╭─────────────────────╮ │ fib_wasm(10::Int32) │ │ Nullable(Int32) │ ├─────────────────────┤ │ 55 │ ╰─────────────────────╯
External UDF Server:灵活解耦的外部 UDF 服务
通过 Arrow Flight 协议与外部 UDF Server 通信,适合将已有的服务和 Databend 互联互通。
Example:
- 启动 UDF Server(Python 示例):
from databend_udf import udf, UDFServer import logging logging.basicConfig(level=logging.INFO) @udf( input_types=["INT"], result_type="INT", skip_null=True, ) def fib(n: int) -> int: a, b = 0, 1 for _ in range(n): a, b = b, a + b return a if __name__ == "__main__": udf_server = UDFServer( location="0.0.0.0:8815" ) udf_server.add_function(fib) udf_server.serve()
- 在 Databend 中注册外部函数:
🐳 root@default:) CREATE OR REPLACE FUNCTION fib_server (INT) RETURNS INT LANGUAGE python HANDLER = 'fib' ADDRESS = 'http://0.0.0.0:8815';
- 调用示例:
🐳 root@default:) select fib_server(10); ╭─────────────────╮ │ fib_server(10) │ │ Nullable(Int32) │ ├─────────────────┤ │ 55 │ ╰─────────────────╯
特点:
- 需要可靠的网络交互
- 支持灵活的参数配置:支持批量处理(默认 65536 行/批)
- 可横向扩展 UDF 服务节点来提高性能
- 适合与现有微服务架构集成, 与 Databend 服务解耦, 可以与任何支持 Arrow Flight 协议的语言交互
性能对比分析
在单机内存环境下(Databend v1.3.0,16GB RAM),计算 fib(x) 的性能对比:
性能测试环境: Intel(R) Core(TM) i9-12900KF 24C archlinux
SQL:
select fib((n % 10) ::Int32) from range(1, 1000000) t(n) ignore_result;
UDF类型 | 平均每行数据执行耗时(us) | 适用场景 |
---|---|---|
Lambda UDF | - | 简单转换、快速原型 |
Python UDF | 0.18 | 复杂逻辑、AI 集成 |
JavaScript UDF | 2.68 | 轻量级数据处理 |
WASM UDF | 0.11 | 高性能处理 |
External UDF | 23.2 | 大规模数据处理 |
*注:External UDF 耗时包含网络通信,实际处理时间会更短。
性能优化建议:
- 简单逻辑优先使用 Lambda UDF
- 复杂计算考虑 Python/JavaScript UDF
- 高并发场景使用 External UDF 并部署多个服务节点
UDF 选型指南
根据您的业务需求选择合适的 UDF 类型:
对比维度 | Lambda UDF | UDF Script | External UDF Server |
---|---|---|---|
开发效率 | ⭐⭐⭐⭐ (纯SQL实现,无需编译) | ⭐⭐⭐ (需编写脚本) | ⭐ (需独立服务部署) |
执行性能 | ⭐⭐⭐⭐ (原生性能) | ⭐⭐⭐ (Python/JS运行时开销, wasm性能最佳) | ⭐⭐ (支持批量处理,动态扩容,网络开销) |
复杂逻辑 | ⭐ (仅限简单表达式) | ⭐⭐⭐ (支持完整编程语言) | ⭐⭐ (需服务化拆分逻辑) |
系统集成 | ⭐ (仅限数据库内部) | ⭐⭐ (需适配语言运行时) | ⭐⭐⭐⭐ (Arrow Flight协议集成) |
实现 | (n)->CASE WHEN n<=1 THEN n ELSE ... | Python/JS实现完整算法逻辑 | 通过Arrow Flight RPC服务暴露计算接口 |
适用场景 | 快速原型/简单转换 | AI集成/复杂数据处理 | 高并发/分布 |
结语:扩展您的数据能力
Databend 的多形态 UDF 支持为数据处理提供了极大的灵活性。无论您需要快速实现简单转换,还是集成复杂业务逻辑,或是构建分布式计算管道,都能找到合适的解决方案。
参考文档:
关于 Databend
Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式湖仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。
👨💻 Databend Cloud:databend.cn
📖 Databend 文档:docs.databend.cn
💻 Wechat:Databend
✨ GitHub:github.com/databendlab...

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
鲲鹏Arm+麒麟V10,国产化信创 K8s 离线部署保姆级教程
Rainbond V6 国产化部署教程,针对鲲鹏 CPU + 麒麟 V10 的离线环境,手把手教你从环境准备到应用上线,所有依赖包提前打包好,步骤写成傻瓜式操作指南。别说技术团队了,照着文档一步步来,让你领导来都能独立完成部署。 一、环境规划 准备至少两台机器。 | 架构 | OS | 作用 | | ----- | ---------------- | ------------------------ | | Arm64 | 任意,Mac 也可以 | 下载离线包 | | Arm64 | 麒麟 V10 | 单机部署 K8s 和 Rainbond | 二、准备离线包 2.1 准备 RKE2 离线包(K8s) 下载 RKE2 v1.30.4 离线安装包。 wget https://pkg.rainbond.com/rke2/v1.30.4+rke2r1/rke2-images-linux-arm64.tar wget https://pkg.rainbond.com/rke2/v1.30.4+rke2r1/rke2.linux-arm64.tar.gz wget https://pkg.ra...
- 下一篇
如何在 DataGrip 中 连接 Databend
本文通过详细的步骤演示了如何新建自定义 Driver 以在 DataGrip 中支持连接 Databend,包括设置 Class、DriverFiles 和URLtemplates。最后,通过新建 Driver 和 DataSource,并在 Databend Cloud 上进行连接测试,确保能成功访问数据库。 安装 DataGrip 首先在 DataGrip 官网 进行下载并安装 DataGrip。 连接 Databend 数据库 新建项目 新建 Driver 由于 DataGrip 默认的 data source 不包含 Databend 数据库,所以需要手动创建 Driver,走 JDBC 的方式连接。 下载 databend jdbc jar 到 maven 或者 databend-jdbc github release page 下载最新版本的 databend-jdbc jar 包。 配置 Driver 选择自定义 JARS,将刚刚下载的 jar 包填写进去。然后将上面的 Class 选择 com.databend.jdbc.DatabendDriver,选择之后 Appl...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Hadoop3单机部署,实现最简伪集群
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能