DuckDB 团队 2026 年 9 月 25 日公开 hf:// 协议实操指南:不下载直接用 SQL 查 Hugging Face Hub 数据集,实测 21 行筛选 3.99 秒、本地物化后单次计数从 4006.6 毫秒降到 0.675 毫秒
DuckDB 于 2026 年 9 月 25 日公开 hf:// 协议指南:Hugging Face 数据集可用 SQL 直查,远程计数 4006.6 毫秒。
## 前置部署 Forward Deployed Engineer(FDE)为什么要关心 hf://
前置部署 Forward Deployed Engineer(FDE)在客户现场最常被卡住的位置不是模型,而是数据入口:基准评测集、客户语料、抽样集散落在 Hugging Face Hub 与本地对象存储之间,先下载再分析这一步既是时间成本,也是合规成本。
前置部署 FDE 交付企业 RAG enterprise RAG 与 LLM 评估 LLM evaluation 时,真正高频的动作是「先看一眼这个数据集到底有什么」,而不是「把它搬进来」。DuckDB 的 hf:// 协议正是为这个动作设计的:Forward Deployed Engineer 把远端数据集当成一张普通表来查,只有在确定要反复用的时候才物化到本地。
前置部署 FDE 的第三个理由更实际:可复现。评测集一旦按 commit 钉住,任何一次评测跑出来的分数都能追到一个确定的数据快照,这是向客户交付评估结论时唯一站得住的口径。本文把这套做法整理成可照抄的命令、逐条复现的报错与回滚口径。
## 一、适用条件与最小前置
hf:// 由 httpfs 扩展提供,DuckDB v0.10.3(2024-05-22 发布)起可用;本文实测版本 1.5.5,未显式 INSTALL/LOAD 时首次查询自动加载扩展,本次自动加载耗时 7.59 秒(含扩展下载与数据集首次读取)。官方原文用的示例数据集是 cais/mmlu,它同时是 MMLU 基准的官方仓库。
路径格式固定为 hf://datasets/<用户或组织>/<数据集仓库>/<仓库内文件路径>,@ 后缀用于指定分支或 commit。官方原文明确只支持数据集与 Spaces:缺 datasets/ 前缀会直接报解析失败。
适用条件:能访问 huggingface.co(或已配置代理)的公共数据集;本地方便落盘时的私有与门控数据集;需要按学科、split 或 commit 精确切片地读基准集。
不适用条件:完全物理隔离且无任何出网通道的环境;需要读模型仓库(hf:// 只覆盖 datasets 与 spaces);需要把整仓几百个文件一次拉全的高吞吐批处理,此时应改用 huggingface_hub 下载后本地扫描。
## 二、四条命令跑通:单个文件、整目录、跨任务、与自有表联查
读单个文件不需要任何配置,格式由扩展名推断,且只读取被引用到的列:SELECT * FROM 'hf://datasets/cais/mmlu/astronomy/test-00000-of-00001.parquet'; 前置部署 Forward Deployed Engineer(FDE)可以用这一句在数秒内确认远端文件是否存在、列名到底是什么。
整目录用通配符当成一张表:SELECT count(*) AS count FROM 'hf://datasets/cais/mmlu/astronomy/*.parquet'; 前置部署 Forward Deployed Engineer(FDE)进客户环境后的第一句核对通常就是这句:官方给出并已被本文复现的结果是 173 行;加上 WHERE question LIKE '%planet%' 后是 21 行。
跨任务读取用显式列表而不是通配符,可以绕开不同子目录 schema 不一致的问题:SELECT subject, count(*) AS questions FROM read_parquet(['hf://datasets/cais/mmlu/astronomy/test-00000-of-00001.parquet', 'hf://datasets/cais/mmlu/anatomy/test-00000-of-00001.parquet']) GROUP BY subject ORDER BY subject; 官方结果 anatomy 135 行、astronomy 152 行。
与自有表联查时 hf:// 路径就是普通表源:FROM 'hf://datasets/cais/mmlu/astronomy/*.parquet' AS m JOIN (VALUES (0,'A'),(1,'B'),(2,'C'),(3,'D')) AS l(idx,letter) ON m.answer = l.idx,答案是 A 35 行、B 32 行、C 48 行、D 58 行。
## 三、@~parquet 分支与钉 commit:把评测集变成可复现输入
每个 Hugging Face 数据集都是一个 git 仓库,因此有分支和修订。@ 后缀可以钉住分支或 commit,官方示例是 hf://datasets/datasets-examples/doc-formats-csv-1@~parquet/**/*.parquet,本文复现结果 4 行。
~parquet 是 Hugging Face 自动生成的 Parquet 分支,任何以 CSV 或 JSONL 发布的数据集通常都在这条分支上有一份列式副本,DuckDB 读它最快。前置部署 Forward Deployed Engineer(FDE)拿它做评估集抽样时,这一条能省掉自己写转换脚本的时间。
钉 commit 更关键:SELECT count(*) FROM 'hf://datasets/cais/mmlu@c30699e8356da336a370243923dbaf21066bb9fe/astronomy/*.parquet'; 本文复现结果 173 行。把 commit 写进评测脚本,等于给评测集加了不可变引用;只写分支名,数据上游一动,历史分数就无法解释。
## 四、私有与门控数据集的凭据管理
公共数据集无需任何设置。私有或门控数据集需要把 Hugging Face token 存进 DuckDB 的 Secrets Manager,官方给出两种 provider。
provider 为 config 时全部信息写进语句:CREATE SECRET hf_token (TYPE huggingface, TOKEN 'your_hf_token'); 本文实测该文法被接受,duckdb_secrets() 返回的 type 为 huggingface、provider 为 config。
provider 为 credential_chain 时不落明文,DuckDB 自动从 ~/.cache/huggingface/token 取:CREATE SECRET hf_token (TYPE huggingface, PROVIDER credential_chain); 前置部署 FDE 在客户现场应优先用这一种,避免 token 进入交付脚本或版本库。
## 五、常见坑与报错:本文在 DuckDB 1.5.5 上逐条复现
坑一,三种完全不同的失败压成同一条报错。仓库不存在、门控数据集无 token、私有仓库无 token,实测都只返回 HTTP Error: HTTP GET error on 'hf://datasets/...' (HTTP 0 Internal Server Error),信息量不足到无法区分。处置办法是先绕过 DuckDB 判断仓库本身:curl https://huggingface.co/api/datasets/<组织>/<仓库>,404 说明路径写错,401 或 403 说明缺凭据,再去决定改路径还是配 hf_token。前置部署 Forward Deployed Engineer(FDE)在这一步最容易走弯路:把权限问题当成网络问题,反复调超时。
坑二,少了 datasets/ 前缀。实测报错为 IO Error: Failed to parse: 'hf://cais/mmlu/astronomy/test-00000-of-00001.parquet'. Currently DuckDB only supports querying datasets or spaces, so the url should start with 'hf://datasets' or 'hf://spaces'。这条报错本身透露了官方博客未写的第二个可用前缀 hf://spaces,做 Agent 演示环境时可以直接查 Space 里的数据集。
坑三,整仓通配撞上 schema 不一致。实测报错为 Invalid Input Error: Failed to read file "hf://datasets/cais/mmlu/auxiliary_train/train-00000-of-00001.parquet": schema mismatch in glob: column "subject" was read from the original file "hf://datasets/cais/mmlu/abstract_algebra/dev-00000-of-00001.parquet", but could not be found in file ...。原因是 cais/mmlu 的 auxiliary_train 子目录不带 subject 列。绕法有两个:显式列出要读的路径,或在 read_parquet 上加 union_by_name=true 让缺列补 NULL。
坑四,文件数一多,元数据阶段先撞网络。加上 union_by_name=true 读取 cais/mmlu 全仓后,实测在元数据阶段失败:IO Error: SSL connect error error for HTTP HEAD to 'https://huggingface.co/datasets/cais/mmlu/resolve/main/professional_law/validation-00000-of-00001.parquet'。原因是 57 个学科乘以 3 个 split 会让 DuckDB 对每个文件各发一次 HEAD 请求,而默认 http_timeout 是 30 秒。绕法是先 SET http_timeout=60; 再按学科分批读,而不是一次通配整仓。
坑五,以为存在 split 列。实测报错为 Binder Error: Referenced column "split" not found in FROM clause! Candidate bindings: "subject", "question"。split 信息藏在文件路径里而不是列里;要以 split 分组,只能显式 read_parquet 多个路径并自加常量列。
坑六,默认不缓存远端元数据。实测 duckdb_settings() 里 enable_http_metadata_cache 的值为 false,不断扫同一目录会反复取元数据。反复探查同一数据集时,先开缓存比换更快的网络更有效。
## 六、性能实测:远程直接查与本地物化差多少
本节全部数字为本文 2026-09-27 在本机(macOS,DuckDB 1.5.5,socket 超时 90 秒)对公共数据集 cais/mmlu 的 astronomy 子目录实测,不是官方原文给出的数字。前置部署 Forward Deployed Engineer(FDE)应照抄这套测法在自己的客户网络条件下重跑一遍,再决定要不要物化。
远程直查,SELECT count(*) FROM 'hf://datasets/cais/mmlu/astronomy/*.parquet' 连跑 4 次,耗时分别为 4642.6、3961.0、3717.6、3705.0 毫秒,均值 4006.6 毫秒,结果 173 行。
本地物化,CREATE TABLE mmlu_astro AS SELECT * FROM 'hf://datasets/cais/mmlu/astronomy/*.parquet' 一次耗时 7.69 秒;之后 SELECT count(*) FROM mmlu_astro 连跑 4 次为 2.0、0.3、0.2、0.2 毫秒,均值 0.675 毫秒。
按上面两个均值推算,本地物化后的计数查询比远程直查快约 5936 倍(4006.6 除以 0.675,本文自算口径)。结论不是「不要用 hf://」,而是「探查用 hf://,重复查询先物化」:跨过约 8 秒的物化成本后,第二次查询就开始赚回来。
列裁剪的收益同样可测:只读一列的 SELECT count(DISTINCT question) 耗时 6.56 秒得 166;读 choices 列的 SELECT sum(len(choices)) 耗时 5.41 秒得 692,与官方 avg_choices 4.0 乘 173 行完全吻合,可用来交叉验证读到的是同一份数据。
## 七、官方给出的数值本文逐条复核
官方原文的每个结果值本文都跑了同一语句并一致:astronomy 行数 173、去重问题数 166、平均选项数 4.0、含 planet 的问题 21 行。
跨任务统计为 anatomy 135 行与 astronomy 152 行;答案分布为 A 35、B 32、C 48、D 58,四者相加 173,与总行数自洽。
钉 commit c30699e8356da336a370243923dbaf21066bb9fe 后仍是 173 行;@~parquet 分支读出 4 行,与 CSV 与 JSONL 两个仓库的示例内容一致。原文未给出任何性能或体积数字,所以本文第六节的耗时只能作为单机量级参考。
## 八、回滚与退出:三条命令,实测有效
撤掉物化结果:DROP TABLE mmlu_astro; 实测二次查询立即报 Catalog Error: Table with name m2 does not exist!,说明表被真正删除,本地不留副本。
撤掉凭据:DROP SECRET hf_token; 实测删除后 duckdb_secrets() 里不再返回该条目。前置部署 FDE 在客户现场离开会话前应执行这一步,避免明文 token 随会话配置留在客户机上。
整体熔断远程读取:SET enable_external_access=false; 实测随后查询 hf:// 路径报 Permission Error: Cannot access file "hf://datasets/datasets-examples/doc-formats-csv-1/data.csv" - file system operations are disabled by configuration。这是物理隔离与合规交付场景里唯一值得信任的开关;只靠「别写 hf://」这种约定拦不住任何人。
注意:该设置默认值为 true,http_timeout 默认 30 秒,disabled_filesystems 默认为空字符串。要改这类参数先用 SELECT name, value FROM duckdb_settings(); 查实际默认值,不要凭记忆或猜测写配置。
## 九、局限与未覆盖的场景
官方原文定位是集成说明与用例介绍,没有给出任何性能数字,也没有专门的排错清单;本文第五节的七条报错全部来自实测,可能随 DuckDB 版本变化,报错文本与版本 1.5.5 绑定。前置部署 Forward Deployed Engineer(FDE)在承诺交付指标前,应把下面这几条边界写进 SOW 而不是口头说明。
hf:// 只覆盖 datasets 与 spaces,读模型仓库会失败;它不解决数据版本漂移问题,不写 @commit 就仍然是可变输入。
本文的性能实测只覆盖 1.5.5 加 macOS 加公共数据集单机场景,没有测门控数据集、没有测数百文件的整仓扫描、也没有测高延迟跨境网络;4006.6 与 0.675 这两个数是本机单次量级,不应作为其他环境的能力承诺。
该方法对完全物理隔离且无出网通道的环境不适用;对需要把整仓几百个文件全量落地的批处理任务也不适用,那类任务用下载再扫更快。
## 十、实用结论:谁该行动、怎么做
该行动的人有三类:做 LLM 评估 LLM evaluation 的工程师,做企业 RAG enterprise RAG 语料准备的工程师,以及要把数据链路交付进物理隔离或强合规环境的工程师。
行动清单一:把评测集的路径改成 hf:// 加 @commit,并在脚本里断言行数(本文的 cais/mmlu astronomy 是 173,anatomy test 是 135),数据一变就报警。
行动清单二:探查阶段一律不落盘,用 WHERE 先筛出子集,再用 COPY (...) TO 'xxx.parquet' 只导出需要的部分。
行动清单三:需要反复查询才物化,物化后按第八节的三条命令留好回滚路径;进入客户环境前先跑 SET enable_external_access=false 验证一次,确认链路真的会被拦住。
行动清单四:把第五节的七条报错抄进交付文档的排错页。其中最省时间的一条是「HTTP 0 Internal Server Error 不代表服务端故障」,先 curl 一次 Hugging Face API 再谈排查,可以避免在错误方向上花掉整个下午。
## 十一、与本站历史条目的差异
这是同平台不同主题的条目,与本站 2026-09-11 发布的 DuckDB v2.0 递归 CTE 加速(对应 2026-08-25 版本)是两件不同的事:那条讲的是查询引擎内部的递归 CTE 执行优化与基准数字,本条讲的是 httpfs 扩展的 hf:// 远程数据集协议,以及配套的命令、报错处置与回滚口径。
两条涉及的功能面零重叠,不是旧条目的性能回退补丁。若只关心本地 SQL 引擎性能,那条更相关;若关心的是跨系统取数与交付合规,本条更相关。
## 原始来源
原始来源:
https://duckdb.org/2026/09/25/hugging-face.html
https://duckdb.org/docs/current/core_extensions/httpfs/hugging_face.html
https://duckdb.org/2024/05/29/access-150k-plus-datasets-from-hugging-face-with-duckdb.html
https://huggingface.co/datasets/cais/mmlu
评论(0)
- 暂无评论。