原文:
towardsdatascience.com/duckdb-and-aws-how-to-aggregate-100-million-rows-in-1-minute-3634eef06b79
当公司需要安全、高性能和可扩展的存储解决方案时,他们往往会倾向于云服务。游戏中最受欢迎的平台之一是 AWS S3——而且有很好的理由——它是一个行业领先的对象存储解决方案,可以用作数据湖。
问题是——你能否在不下载的情况下聚合 S3 桶中的数据?并且你能快速完成吗?
答案是是,对两个问题都是。DuckDB 允许你通过httpfs扩展直接连接到你的 S3 桶。你将通过聚合大约 1110 万行数据来学习如何使用它,这些数据分布在 37 个Parquet文件之间。
剧透警告: 这将花费你大约一分钟。
注意: 我写这篇帖子是因为我在寻找一个更高效的 Pandas 替代品。我的目标是本地对大型数据集进行分析,而不是选择云解决方案。我与 DuckDB 或 AWS 没有任何关联。
AWS S3 设置
首先,你需要一个 AWS 账户和一个 S3 桶。你还需要创建一个 IAM 用户,你可以为该用户生成一个访问密钥。
关于数据,我已经从以下链接下载了从 2021 年 1 月到 2024 年 1 月的Yellow Taxi数据Parquet文件:
- 纽约市出租车和豪华轿车委员会(TLC)行程记录数据于 2024 年 4 月 18 日从
www.nyc.gov/site/tlc/about/tlc-trip-record-data.page](https://www.nyc.gov/site/tlc/about/tlc-trip-record-data.page)获取。数据免费使用。许可信息可在 nyc.gov 上找到。
这就是将其加载到 S3 桶中的样子:
图像 1 – S3 桶中的 Parquet 文件(作者提供)
现在桶中包含 37 个 Parquet 文件,占用 1.79 GB 的空间,包含超过 1110 万行。
DuckDB AWS S3 设置
在 Python 端设置需要duckdb库和 DuckDB 的httpfs扩展。假设你已经安装了库(简单的pip安装),导入它,并创建一个新的连接:
import duckdb
conn = duckdb.connect()
DuckDB httpfs 扩展
httpfs 扩展,以及其他功能,允许你将文件写入/读取到指定的 AWS S3 桶中。
使用以下 Python 命令安装它并加载它(只运行一次安装):
conn.execute("""
INSTALL httpfs;
LOAD httpfs;
""").df()
你应该会看到一个类似的成功消息:
图像 2 – 安装和加载 httpfs 扩展(图片由作者提供)
DuckDB S3 配置
至于 S3 配置,向 DuckDB 提供区域、访问密钥和秘密访问密钥:
conn.execute("""
SET s3_region = '<your-region>';
SET s3_access_key_id = '<your-access-key>';
SET s3_secret_access_key = '<your-secret-key>';
""").df()
您应该再次看到成功消息:
图像 3 – DuckDB S3 配置(图片由作者提供)
就这样!现在您可以直接从 DuckDB 查询 S3 数据。
Python 和 DuckDB – 如何从 AWS 获取数据
本节将展示运行两个查询——简单计数和聚合——所需的时间,这两个查询存储在 S3 上的 37 个 Parquet 文件中。
查询 #1 – 简单计数
要从 S3 存储桶读取 Parquet 数据,使用 parquet_scan() 函数并提供存储在根路径下所有 Parquet 文件的 glob 路径。只需记住更改存储桶名称:
res_count = conn.execute("""
select count(*)
from parquet_scan('s3://<your-bucket-name>/*.parquet');
""").df()
res_count
获取超过 1.11 亿的计数只需 7 秒:
图像 4 – DuckDB 计数结果(图片由作者提供)
查询 #2 – 按月度汇总统计
现在,让我们计算所有 Parquet 文件的总计统计信息。目标是获取按月度分组的一定列的计数、总和和平均值:
res_agg = conn.execute("""
select
period,
count(*) as num_rides,
round(avg(trip_duration), 2) as avg_trip_duration,
round(avg(trip_distance), 2) as avg_trip_distance,
round(sum(trip_distance), 2) as total_trip_distance,
round(avg(total_amount), 2) as avg_trip_price,
round(sum(total_amount), 2) as total_trip_price,
round(avg(tip_amount), 2) as avg_tip_amount
from (
select
date_part('year', tpep_pickup_datetime) as trip_year,
strftime(tpep_pickup_datetime, '%Y-%m') as period,
epoch(tpep_dropoff_datetime - tpep_pickup_datetime) as trip_duration,
trip_distance,
total_amount,
tip_amount
from parquet_scan('s3://duckdb-bucket-20240422/*.parquet')
where trip_year >= 2021 and trip_year <= 2024
)
group by period
order by period
""").df()
res_agg
进行此聚合操作只需超过一分钟:
图像 5 – DuckDB 聚合结果(图片由作者提供)
作为参考,当文件保存在本地磁盘上时,相同的操作耗时 不到 2 秒。Pandas 完成相同任务需要超过 11 分钟。
总结 DuckDB 和 AWS 在 Python 中的应用
总体而言,如果您在 S3 上存储了大量的数据,DuckDB 是您的朋友。您可以在不下载文件的情况下快速分析和聚合数据——这可能会由于隐私和安全问题而完全不允许。
您还可以将 DuckDB 用作两个 AWS S3 存储层之间的分析和 聚合层。原始数据进入,聚合数据输出——希望是进入另一个存储桶或子目录。
继续阅读:
95

被折叠的 条评论
为什么被折叠?



