news 2026/9/25 4:41:12

Apache DataFusion 函数文档化机制解析:datafusion-doc 与 `[user_doc]` 宏实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache DataFusion 函数文档化机制解析:datafusion-doc 与 `[user_doc]` 宏实战指南
  • 大数据
  • 数据分析
  • 后端

【免费下载链接】datafusion

Apache DataFusion SQL Query Engine

项目地址:https://gitcode.com/gh_mirrors/datafu/datafusion
点击查看免费下载

Apache DataFusion 是一个用 Rust 编写的可扩展查询执行框架,使用 Apache Arrow 作为内存数据格式。在 DataFusion 中,内置的标量函数、聚合函数和窗口函数并非"散落在文档里",而是通过datafusion-doc子模块提供的结构化类型与过程宏,在源码中就地声明、再由工具自动生成官方 SQL 函数文档。本文将以仓库中的 datafusion/doc/README.md 为核心骨架,深入datafusion-doccrate 的Documentation/DocSection/DocumentationBuilder结构、#[user_doc]声明式宏以及整套文档生成管线,读完你将掌握如何为自己的 UDF 编写能被官方文档机制识别、渲染的规范文档。

一、datafusion-doc 是什么:UDF 文档化子模块的定位

按照 datafusion/doc/README.md 的说明,DataFusion 是一个用 Rust 编写的可扩展查询执行框架(extensible query execution framework),并将 Apache Arrow 作为内存格式(in-memory format)。datafusion-doc这个 crate 是 DataFusion 的一个子模块,它的职责非常聚焦:

This crate is a submodule of DataFusion that provides structures and macros for documenting user defined functions.

即:提供用于记录(文档化)用户自定义函数(UDF)的数据结构与宏。这里的 UDF 涵盖三类:标量函数(ScalarUDFImpl)、聚合函数(AggregateUDFImpl)和窗口函数(WindowUDFImpl)。

从 datafusion/doc/Cargo.toml 可以看到该模块的包名为datafusion-doc、库名为datafusion_doc,描述为 "Documentation module for DataFusion query engine"。

README 还给出了一个重要的使用建议:

Most projects should use thedatafusioncrate directly, which re-exports this module. If you are already using thedatafusioncrate, there is no reason to use this crate directly in your project as well.

也就是说,datafusion-doc是 DataFusion 内部模块化拆分的产物,对外并不需要用户单独依赖。在仓库内部,datafusion/core/src/bin/print_functions_docs.rs 直接以use datafusion_expr::{DocSection, Documentation, aggregate_doc_sections, scalar_doc_sections, window_doc_sections, ...}的方式引用这些符号,说明它们经由datafusion_expr再导出、并最终随datafusion主 crate 一并暴露给使用者。因此,应用开发者只要依赖datafusion主 crate,就能拿到完整的 UDF 文档化能力。

二、核心数据结构:Documentation / DocSection / DocumentationBuilder

datafusion-doc的全部核心类型都定义在 datafusion/doc/src/lib.rs 中,由三条主线组成:最终产物Documentation、分区标记DocSection、以及构建器DocumentationBuilder。

2.1 Documentation:一份 UDF 文档的完整描述

Documentation结构体(lib.rs)承载了单个 UDF 的全部文档信息,字段含义如下:

字段类型含义
doc_sectionDocSection该 UDF 在文档中归属的分区(例如 "Math Functions")
descriptionString函数的功能描述
syntax_exampleString语法示例,如"ascii(str)"
sql_exampleOption<String>一段 SQL 示例,通常以 SQL 提示符查询与输出形式给出;除最简单的函数外强烈建议提供
argumentsOption<Vec<(String, String)>>参数列表,按添加顺序展示,二元组左侧为参数名、右侧为参数描述
alternative_syntaxOption<Vec<String>>该函数其它可用的语法写法
related_udfsOption<Vec<String>>相关函数名列表,值必须与相关 UDF 的 name 完全一致

值得注意的是,DataFusion 官方的 SQL 函数文档正是由这些结构体自动生成的("The DataFusion SQL function documentation is automatically generated from these structs"),UDF 的名称取自ScalarUDFImpl::name、AggregateUDFImpl::name或WindowUDFImpl::name。

2.2 DocSection:把函数归入正确的文档分区

DocSection(lib.rs)用于指定文档中的展示分区,包含三个字段:

  • include:是否将该分区包含进公开文档(true包含,false不包含);
  • label:展示标签,例如"Math Expressions";
  • description:可选的分区级描述。

其Default实现(lib.rs)返回include: true、label: "Default"、description: None,适合那些不出现在 DataFusion 官方文档中的自定义 UDF——即默认可见,但没有专属分类。

2.3 DocumentationBuilder:链式构建文档

DocumentationBuilder采用经典的 builder 模式(lib.rs),通过Documentation::builder(doc_section, description, syntax_example)创建,随后以链式方法补齐可选信息:

方法作用
with_doc_section覆盖文档分区
with_description覆盖功能描述
with_syntax_example覆盖语法示例
with_sql_example添加 SQL 示例
with_argument(name, description)追加一个参数说明(按添加顺序展示)
with_standard_argument(name, expression_type)追加一个标准"表达式"参数说明,自动拼接固定的模板文案
with_alternative_syntax(syntax)追加一种替代语法
with_related_udf(name)追加一个相关函数
build()构建出最终的Documentation(doc_section、description、syntax_example未设置时会 panic)

with_standard_argument会生成统一风格的参数描述:传入Some("String")时渲染为 "String expression to operate on. Can be a constant, column, or function, and any combination of operators.",传入None时则以 "The" 开头渲染同样的模板,保证文档中大量通用参数表述一致。

lib.rs自带的 doctest 展示了最小可用写法:

use datafusion_doc::{DocSection, Documentation}; let doc_section = DocSection { include: true, label: "Display Label", description: None, }; let documentation = Documentation::builder(doc_section, "Add one to an int32".to_owned(), "add_one(2)".to_owned()) .with_argument("arg_1", "The int32 number to add one to") .build();

三、预定义文档分区:三种 UDF 各自可用的 DocSection

为了让内置函数在官方文档中归类统一,datafusion-doc在三个子模块中预定义了各类型 UDF 的标准分区。#[user_doc]宏(见下文)会按label查找并匹配这些预定义分区。

3.1 标量函数分区(scalar_doc_sections)

定义于 datafusion/doc/src/udf.rs,共 12 个分区:

  • Math Functions
  • Conditional Functions
  • String Functions
  • Binary String Functions
  • Regular Expression Functions(自带分区描述,说明 DataFusion 使用 PCRE-like 正则语法,支持i、m、s、R、U等可选标志)
  • Time and Date Functions
  • Array Functions
  • Struct Functions
  • Map Functions
  • Hashing Functions
  • Union Functions(自带描述,强调 union 数据类型即 tagged unions / variant types / enums / sum types,且与 SQL 的 UNION 运算符无关)
  • Other Functions

3.2 聚合函数分区(aggregate_doc_sections)

定义于 datafusion/doc/src/udaf.rs,共 3 个分区:General Functions、Statistical Functions、Approximate Functions。

3.3 窗口函数分区(window_doc_sections)

定义于 datafusion/doc/src/udwf.rs,共 3 个分区:

  • Aggregate Functions(自带描述 "All aggregate functions can be used as window functions.")
  • Ranking Functions
  • Analytical Functions

四、声明式文档:#[user_doc]过程宏

手写DocumentationBuilder链式代码仍然繁琐,因此 DataFusion 在datafusion-macros中提供了#[user_doc(...)]过程宏(datafusion/macros/src/user_doc.rs),把文档写成紧邻函数结构的声明式属性,再由宏在编译期自动生成DocumentationBuilder调用代码。

宏支持的属性项包括:doc_section(label = "...")、description = "..."、syntax_example = "..."、sql_example = r#"... "#、standard_argument(name = "...", prefix = "...")、argument(name = "...", description = "...")、alternative_syntax = "..."、related_udf(name = "...")。其中doc_section会尝试按 label 查找预定义的DocSection。

以真实的内置函数coalesce为例(datafusion/functions/src/core/coalesce.rs):

#[user_doc( doc_section(label = "Conditional Functions"), description = "Returns the first of its arguments that is not _null_. Returns _null_ if all arguments are _null_. This function is often used to substitute a default value for _null_ values.", syntax_example = "coalesce(expression1[, ..., expression_n])", sql_example = r#"```sql > select coalesce(null, null, 'datafusion'); +----------------------------------------+ | coalesce(NULL,NULL,Utf8("datafusion")) | +----------------------------------------+ | datafusion | +----------------------------------------+ ```"#, argument( name = "expression1, expression_n", description = "Expression to use if previous expressions are _null_. Can be a constant, column, or function, and any combination of arithmetic operators. Pass as many expression arguments as necessary." ) )] #[derive(Debug, PartialEq, Eq, Hash)] pub struct CoalesceFunc { pub(super) signature: Signature, }

宏的文档注释(user_doc.rs)说明了它展开后生成的代码形态:为结构体生成fn doc(&self) -> Option<&datafusion_doc::Documentation>方法,内部用std::sync::LazyLock缓存一个Documentation::builder(...)链式调用的结果,例如:

fn doc(&self) -> Option<&datafusion_doc::Documentation> { static DOCUMENTATION: std::sync::LazyLock<datafusion_doc::Documentation> = std::sync::LazyLock::new(|| { datafusion_doc::Documentation::builder( datafusion_doc::DocSection { include: true, label: "Time and Date Functions", description: None, }, "Converts a value to a date (`YYYY-MM-DD`).".to_string(), "to_date(expression[, ..., format_n])".to_string(), ) .with_sql_example(...) .with_standard_argument("expression", "String".into()) .with_argument("format_n", ...) .build() }); Some(&DOCUMENTATION) }

也就是说,#[user_doc]只是声明式语法糖,最终仍落到第二节中的Documentation/DocumentationBuilder之上。生成的文档可通过ScalarUDFImpl、AggregateUDFImpl、WindowUDFImpl的documentation()方法取出(见 datafusion/expr/src/udf.rs 及 datafusion/expr/src/udaf.rs、datafusion/expr/src/udwf.rs 中对应的documentation方法)。

五、从结构体到官方 SQL 文档:完整的生成管线

数据最终落地的环节是文档生成器。datafusion/core下提供了print_functions_docs二进制(datafusion/core/src/bin/print_functions_docs.rs),它遍历当前会话注册的全部函数,按aggregate/scalar/window三种类型把每个 UDF 的Documentation渲染成 Markdown 输出到 stdout。

围绕它的自动化脚本是 dev/update_function_docs.sh,执行流程大致为:

  1. 以仓库根目录为基准,默认输出目录为docs/source/user-guide/sql,可通过--output-dir DIR覆盖;
  2. 依次生成三个页面,例如聚合函数页使用命令:
    cargo run --manifest-path datafusion/core/Cargo.toml --features docs_generation --bin print_functions_docs -- aggregate
  3. 将渲染结果连同固定的文件头写入docs/source/user-guide/sql/aggregate_functions.md、scalar_functions.md、window_functions.md。

生成的 Markdown 文件头部会明确标注:"This file was generated by the dev/update_function_docs.sh script. Do not edit it manually as changes will be overwritten.",并提示应修改 UDF 的documentation()函数或脚本本身来更新文档。这些页面最终通过 docs/source/user-guide/sql/index.rst 挂入用户指南。

以coalesce为例,docs/source/user-guide/sql/scalar_functions.md 中对应的章节正是由#[user_doc]属性中的描述、语法示例、SQL 示例渲染而来:

> select coalesce(null, null, 'datafusion'); +----------------------------------------+ | coalesce(NULL,NULL,Utf8("datafusion")) | +----------------------------------------+ | datafusion | +----------------------------------------+

由此可见:源码中的#[user_doc]是唯一事实来源,print_functions_docs是渲染器,update_function_docs.sh负责把渲染结果落盘为官方文档。

六、编写 UDF 文档的规范与约束

结合lib.rs的文档注释与宏实现,为 UDF 编写文档时有几条明确的规范需要遵守:

  1. Markdown 格式:Documentation中所有字符串都必须使用 Markdown 格式书写(lib.rs明确要求),包括描述中的强调、代码与链接。
  2. 当前仅支持单语言:文档目前只支持一种语言,所有文本应使用英文。
  3. related_udfs必须同类型且名字精确:相关函数的值应与对应 UDF 的name()完全一致,并且必须是同一种 UDF 类型(标量、聚合或窗口),否则无法正确生成互链。
  4. doc_section标签需匹配预定义分区:#[user_doc]宏会按label查找预定义的DocSection,因此自定义分区标签时应参考第三节中列出的标准分区集合;对不出现在官方文档中的自定义 UDF,可使用DocSection::default()(include: true、label 为"Default")。
  5. 尽量提供sql_example:除最简单的函数外,官方强烈建议提供带实际输出结果的 SQL 示例,这能显著提升文档的可读性与可验证性。
  6. 不要手工编辑生成文件:docs/source/user-guide/sql下的函数文档由脚本生成,应通过修改 UDF 实现中的文档声明后重新运行 dev/update_function_docs.sh 来更新。

此外,Documentation还提供了一个to_doc_attribute()方法(lib.rs),能把已有的代码式文档结构输出为等价的#[user_doc(...)]属性文本——这是从"代码构建文档"迁移到"属性声明文档"的半自动化辅助工具,文档注释中说明它可用于 UDF 文档生成方式的迁移过渡,迁移完成后即可安全移除。

结语

datafusion-doc虽然只是 DataFusion 仓库中的一个文档子模块,却完整承载了"UDF 文档从声明到发布"的整条链路:Documentation/DocSection/DocumentationBuilder提供结构化数据模型,#[user_doc]宏让文档可以伴随函数实现就地书写,print_functions_docs与update_function_docs.sh则把源码中的声明自动渲染为官方 SQL 函数页面。理解了这套机制,无论是为 DataFusion 贡献内置函数,还是在自己的扩展中维护 UDF 文档,都能做到"一处声明、处处生效",并保证文档与实现永远同源。

  • 大数据
  • 数据分析
  • 后端

【免费下载链接】datafusion

Apache DataFusion SQL Query Engine

项目地址:https://gitcode.com/gh_mirrors/datafu/datafusion
点击查看免费下载
上一篇:抖音批量下载完全指南:单条视频到整页作品一键搞定
下一篇:10分钟搭建MediaMTX自动化部署流水线:GitLab CI/CD与Jenkins实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:39:54

全志H5平台AP6212 WiFi移植实战:SDIO驱动、设备树与固件全链路调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:39:13

STM32学习不贪不放:核心外设组合拳与实战排错指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:39:08

ExternalDNS 对接 Pi-hole 自定义 DNS:从部署到验证的完整指南

云原生 【免费下载链接】external-dns Configure external DNS servers dynamically from Kubernetes resources 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ex/external-dns 点击查看 免费下载 导读 本指南基于 external-dns 官方教程&#xff0c;讲解如何将 Kub…

作者头像 李华
网站建设 2026/9/25 4:38:54

单机记忆翻牌游戏开发实战:状态机、洗牌算法与移动端优化

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 4:38:21

Codex 重大更新:AGENTS.md 与 Skills 智能体工作流实战指南

1. 从"焚决"这个词说起&#xff1a;Codex 这次到底更新了什么"焚决"这个词最近在开发者圈子里传得挺凶&#xff0c;第一次看到的时候我还以为是哪个玄幻小说的功法名。后来才搞明白&#xff0c;这是社区里对 Codex 一次重大能力升级的戏称——大概意思是&q…

作者头像 李华
网站建设 2026/9/25 4:37:57

用树莓派开源方案DIY CarPlay车机:从编译到点亮屏幕全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华