DuckDB 和 AWS——如何在 1 分钟内聚合 1 亿行数据

原文: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 桶中的样子:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a529b5ada11fb29efb324cf71e061c11.png

图像 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()

你应该会看到一个类似的成功消息:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fc1a447d3f8c1208c0984cc357bfeb63.png

图像 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()

您应该再次看到成功消息:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/771a186d23a8cbe4c2c4ae9554ecf617.png

图像 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 秒:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/aa2e1c7f8bb1f75a098e9ff6a48c9daf.png

图像 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

进行此聚合操作只需超过一分钟:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/be0d4b2dfcc57477c225c3aef234d359.png

图像 5 – DuckDB 聚合结果(图片由作者提供)

作为参考,当文件保存在本地磁盘上时,相同的操作耗时 不到 2 秒。Pandas 完成相同任务需要超过 11 分钟。


总结 DuckDB 和 AWS 在 Python 中的应用

总体而言,如果您在 S3 上存储了大量的数据,DuckDB 是您的朋友。您可以在不下载文件的情况下快速分析和聚合数据——这可能会由于隐私和安全问题而完全不允许。

您还可以将 DuckDB 用作两个 AWS S3 存储层之间的分析和 聚合层。原始数据进入,聚合数据输出——希望是进入另一个存储桶或子目录。

继续阅读:

如何在 SQL 中训练决策树分类器…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值