duckdb,单机高效处理海量数据

当我们用pandas处理百万级,千万级,乃至上亿行的数据时,缓慢的速度常常让我们痛苦不堪。

这时候,不妨试试duckdb.

duckdb在本地单机即可运行,性能非常高。

它可以像spark那样使用sql语句进行数据分析和数据转换。

当处理几千万行以上的数据时,它的效率通常是pandas的几十几百倍。

公众号算法美食屋后台回复关键词:源码,获取本文notebook源代码。

duckdb个库的用法非常简单,核心API只有以下几个。

 
 
import duckdb


#输入建表:可以从parquet,pandas dataframe建表
tb = duckdb.read_parquet('input_data.parquet') 
tb = duckdb.from_df(df) #从pandas转换


#分析转换:执行sql,支持自定义函数UDF
tb2 = duckdb.sql('select * from tb  where val>1000 and val<10000  order by val')
duckdb.create_function('myfunc',myfunc,[duckdb.typing.VARCHAR],duckdb.typing.VARCHAR)  


#输出落表: 推荐导出成parquet格式,效率最高
tb2.to_parquet('output_data.parquet')
df2 = tb2.to_df() #也可以转换成pandas

一,输入建表

 
 
import numpy as np
import pandas as pd
import duckdb
 
 
#生成示例数据(5000万行)
dfdemo = pd.DataFrame(
    {
        'category': np.random.choice(list('ABCDEF'), 50000000),
        'val': np.round(np.random.uniform(0, 1000000, 50000000), 3)
    }
)
dfdemo.to_parquet('dfdemo.parquet', index=False)

对比读取数据速度,duckdb比pandas快几十倍

b121be735647b59b2a887689730769fa.png

二,SQL分析

1, 基本查询

where查询对比 (duckdb比pandas快20倍)

74ec6f9ff3fb2d7cf7fcfe8da00cc979.png

groupby 操作对比 (duckdb比pandas快40倍)

387ef64752bde48b7d2df7a1e041507c.png

join 操作对比 (duckdb比pandas快600倍)

21fac3ede688e9ca136f6244618f1c06.png

2,自定义函数UDF

pyspark的一个优点是可以在sql中使用注册自定义函数(UDF),比较灵活。

那么duckdb支持在sql中使用注册自定义函数吗?of course!

⚫️ 注册方法:使用create_function方法来注册一个Python函数作为UDF。需要提供函数名称、Python函数、参数类型和返回类型。

⚫️ 类型注解:如果Python函数有类型注解,可以省略parameters和return_type参数,DuckDB会根据注解自动推断。

⚫️ 空值处理:默认情况下,当UDF接收到NULL值时,会立即返回NULL。如果需要特殊处理,可以设置null_handling="special"。

⚫️ 异常处理:默认情况下,如果Python函数抛出异常,DuckDB会重新抛出该异常。如果希望改为返回null,可以设置exception_handling="return_null"。

⚫️ 副作用:如果UDF的结果受随机性影响,需要将side_effects设置为True。

⚫️ 使用Arrow:如果函数需要接收Arrow数组,设置type='arrow'。这会通知系统提供Arrow数组给函数,并期望函数返回相同数量的数组。

⚫️ 使用Native:当设置type='native'时,函数将按单个元组接收数据,并返回单个值。这适用于与不操作Arrow的Python库交互,如faker。

a5820fafc964db27acd98aa15276c76e.png

 
 
import duckdb
from faker import Faker
def generate_random_name(i:int) -> str: 
    fake = Faker()
    fake.random.seed(i)
    
    #演示异常逻辑处理
    #if i%10==0:
    #    raise Exception('error') 
    
    name = fake.name()
    return name


#移除UDF
if 'random_name' in get_rand_funs()['function_name'].tolist():
    duckdb.remove_function('random_name')  


    
#注册UDF
duckdb.create_function("random_name", generate_random_name, 
                       [duckdb.typing.BIGINT], duckdb.typing.VARCHAR, 
                       exception_handling="return_null")

3ef7247fb313517388e8c7bbcc7f245d.png

bfe9ee7625153408b3adced07dfc9b95.png

三,输出落表

 
 
tb_student.to_parquet('student.parquet')

公众号算法美食屋后台回复关键词:源码,获取本文notebook源代码。

万水千山总是情,点个在看行不行?😋😋

bf4536a386a5ea34f1e3e8d8628ec92c.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值