httpfs 扩展支持使用 S3 API 对对象存储服务器上的文件进行读取/写入/通配符匹配。S3 提供了一套标准的 API 来读取和写入远程文件(而早于 S3 的常规 http 服务器不提供通用的写入 API)。DuckDB 符合目前行业存储提供商普遍采用的 S3 API 标准。
平台
httpfs 文件系统已通过 AWS S3、Minio、Google Cloud 和 lakeFS 的测试。其他实现 S3 API 的服务(如 Cloudflare R2)也应该可以使用,但可能并非所有功能都受支持。
下表显示了 httpfs 的每个功能所需的 S3 API 部分。
| 功能 | 所需的 S3 API 功能 |
|---|---|
| 公共文件读取 | HTTP 范围(Range)请求 |
| 私有文件读取 | 密钥或会话令牌认证 |
| 文件通配符匹配 | ListObjectsV2 |
| 文件写入 | 分段上传(Multipart upload) |
配置与认证
配置 S3 端点并进行认证的首选方式是使用 secrets。可以使用多个密钥提供程序。
要从已弃用的 S3 API 迁移,请使用带 profile 的已定义密钥。请参阅“基于 Profile 加载密钥”一节。
config 提供程序
默认提供程序 config(即用户配置)允许通过手动提供密钥来访问 S3 存储桶。例如
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER config,
KEY_ID 'AKIAIOSFODNN7EXAMPLE',
SECRET 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
REGION 'us-east-1'
);
提示:如果您收到 IO 错误(
Connection error for HTTP HEAD),请通过ENDPOINT 's3.your-region.amazonaws.com'显式配置端点。
现在,要使用上述密钥进行查询,只需查询任何以 s3:// 为前缀的文件即可
SELECT *
FROM 's3://your-bucket/your_file.parquet';
credential_chain 提供者
credential_chain 提供程序允许使用 AWS SDK 提供的机制自动获取凭证。例如,使用 AWS SDK 默认提供程序
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain
);
同样,要使用上述密钥查询文件,只需查询任何以 s3:// 为前缀的文件即可。
DuckDB 还允许使用 CHAIN 关键字指定特定的链。这接受一个分号分隔的提供程序列表(a;b;c),系统将按顺序尝试这些提供程序。例如
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain,
CHAIN 'env;config'
);
CHAIN 的可能值如下
credential_chain 提供程序还允许覆盖自动获取的配置。例如,要自动加载凭证,然后覆盖区域设置,请运行
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain,
CHAIN config,
REGION 'eu-west-1'
);
基于 Profile 加载密钥
如果凭证对应的 profile 未在 AWS_PROFILE 环境变量中定义,或未作为基于 AWS SDK 优先级的默认 profile 定义,则要加载该凭证,请运行
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain,
CHAIN config,
PROFILE 'my_profile'
);
这种方法等同于已弃用的 S3 API 的 load_aws_credentials('⟨my_profile⟩') 方法。
S3 密钥参数概述
以下是可用于 config 和 credential_chain 提供程序的支持参数的完整列表
| 名称 | 描述 | 密钥 | 类型 | 默认值 |
|---|---|---|---|---|
ENDPOINT |
指定自定义 S3 端点 | S3, GCS, R2 |
字符串 |
S3 为 s3.amazonaws.com, |
KEY_ID |
所使用的密钥 ID | S3, GCS, R2 |
字符串 |
- |
REGION |
认证区域(应与要查询的存储桶区域匹配) | S3, GCS, R2 |
字符串 |
us-east-1 |
SECRET |
所使用的密钥对应的秘钥内容 | S3, GCS, R2 |
字符串 |
- |
SESSION_TOKEN |
可选,可传入会话令牌以使用临时凭证 | S3, GCS, R2 |
字符串 |
- |
URL_COMPATIBILITY_MODE |
当 URL 包含特殊字符时可能有用 | S3, GCS, R2 |
BOOLEAN |
true |
URL_STYLE |
vhost 或 path |
S3, GCS, R2 |
字符串 |
S3 为 vhost,R2 和 GCS 为 path |
USE_SSL |
是否使用 HTTPS 或 HTTP | S3, GCS, R2 |
BOOLEAN |
true |
ACCOUNT_ID |
用于生成端点 URL 的 R2 账户 ID | R2 |
字符串 |
- |
KMS_KEY_ID |
用于 S3 服务器端加密的 AWS KMS (密钥管理服务) 密钥 | S3 |
字符串 |
- |
REQUESTER_PAYS |
允许使用“请求者付费”的 S3 存储桶 | S3 |
BOOLEAN |
false |
平台特定密钥类型
S3 密钥
httpfs 扩展支持使用 KMS_KEY_ID 选项通过 AWS KMS 在 S3 上进行服务器端加密
CREATE OR REPLACE SECRET secret (
TYPE s3,
PROVIDER credential_chain,
CHAIN config,
REGION 'eu-west-1',
KMS_KEY_ID 'arn:aws:kms:region:account_id:key/key_id',
SCOPE 's3://bucket-sub-path'
);
R2 密钥
虽然 Cloudflare R2 使用常规 S3 API,但 DuckDB 拥有一种特殊的密钥类型 R2,使配置变得更简单
CREATE OR REPLACE SECRET secret (
TYPE r2,
KEY_ID 'AKIAIOSFODNN7EXAMPLE',
SECRET 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
ACCOUNT_ID 'my_account_id'
);
注意添加了用于为您生成正确端点 URL 的 ACCOUNT_ID。还要注意,R2 密钥也可以同时使用 CONFIG 和 credential_chain 提供程序。但是,由于 DuckDB 内部使用 AWS 客户端,当使用 credential_chain 时,客户端会在标准的 AWS 凭证位置(环境变量、凭证文件等)中搜索 AWS 凭证。因此,您的 R2 凭证必须作为 AWS 环境变量(AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY)提供,以便凭证链正常工作。最后,R2 密钥仅在使用以 r2:// 开头的 URL 时才可用,例如
SELECT *
FROM read_parquet('r2://some-file-that-uses-an-r2-secret.parquet');
GCS 密钥
虽然 DuckDB 通过 S3 API 访问 Google Cloud Storage,但 DuckDB 拥有一种特殊的密钥类型 GCS,使配置变得更简单
CREATE OR REPLACE SECRET secret (
TYPE gcs,
KEY_ID 'my_hmac_access_id',
SECRET 'my_hmac_secret_key'
);
重要提示:KEY_ID 和 SECRET 值必须是专门为 Google Cloud Storage 互操作性生成的 HMAC 密钥。它们与常规 GCP 服务账户密钥或访问令牌不同。您可以按照管理 HMAC 密钥的 Google Cloud 文档创建 HMAC 密钥。
请注意,上述密钥将自动配置正确的 Google Cloud Storage 端点。还要注意,GCS 密钥也可以同时使用 CONFIG 和 credential_chain 提供程序。但是,由于 DuckDB 内部使用 AWS 客户端,当使用 credential_chain 时,客户端会在标准的 AWS 凭证位置中搜索 AWS 凭证。因此,您的 GCS HMAC 密钥必须作为 AWS 环境变量(AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY)提供,以便凭证链正常工作。最后,GCS 密钥仅在使用以 gcs:// 或 gs:// 开头的 URL 时才可用,例如
SELECT *
FROM read_parquet('gcs://some/file/that/uses/a/gcs/secret.parquet');
读取
现在从 S3 读取文件非常简单
SELECT *
FROM 's3://your-bucket/filename.extension';
部分读取
httpfs 扩展支持从 S3 存储桶进行部分读取。
读取多个文件
也可以读取多个文件,例如
SELECT *
FROM read_parquet([
's3://your-bucket/filename-1.parquet',
's3://your-bucket/filename-2.parquet'
]);
通配符匹配
文件通配符匹配通过 ListObjectsV2 API 调用实现,允许使用类似文件系统的通配符模式匹配多个文件,例如
SELECT *
FROM read_parquet('s3://your-bucket/*.parquet');
此查询匹配存储桶根目录下所有具有 Parquet 扩展名的文件。
支持多种匹配功能,例如 * 匹配任意数量的任意字符,? 匹配任意单个字符,或 [0-9] 匹配字符范围内的单个字符
SELECT count(*) FROM read_parquet('s3://your-bucket/folder*/100?/t[0-9].parquet');
使用通配符时的一个有用功能是 filename 选项,它会添加一个名为 filename 的列,其中编码了特定行所来源的文件路径
SELECT *
FROM read_parquet('s3://your-bucket/*.parquet', filename = true);
这例如可能会导致以下结果
| column_a | column_b | 文件名 |
|---|---|---|
| 1 | examplevalue1 | s3://bucket-name/file1.parquet |
| 2 | examplevalue1 | s3://bucket-name/file2.parquet |
Hive 分区
DuckDB 还提供了对 Hive 分区方案的支持,该方案在使用 HTTP(S) 和 S3 端点时可用。
写入
写入 S3 使用分段上传 API。这允许 DuckDB 高速、稳健地上传文件。写入 S3 适用于 CSV 和 Parquet
COPY table_name TO 's3://your-bucket/filename.extension';
分区写入 S3 也同样有效
COPY table TO 's3://your-bucket/partitioned' (
FORMAT parquet,
PARTITION_BY (part_col_a, part_col_b)
);
系统会对现有文件/目录进行自动检查(目前检查较为保守,在 S3 上会增加一点延迟)。要禁用此检查并强制写入,可以添加 OVERWRITE_OR_IGNORE 标志
COPY table TO 's3://your-bucket/partitioned' (
FORMAT parquet,
PARTITION_BY (part_col_a, part_col_b),
OVERWRITE_OR_IGNORE true
);
写入文件的命名方案如下所示
s3://your-bucket/partitioned/part_col_a=val/part_col_b=val/data_thread_number.parquet
配置
针对 S3 上传还有一些额外的配置选项,不过默认值应该足以满足大多数用例。
| 名称 | 描述 |
|---|---|
s3_uploader_max_parts_per_file |
用于分段大小计算,请参阅 AWS 文档 |
s3_uploader_max_filesize |
用于分段大小计算,请参阅 AWS 文档 |
s3_uploader_thread_limit |
最大上传线程数 |