背景:
DuckDB 允许直接查询 parquet 文件。例如con.execute("从'Hierarchy.parquet'中选择*)
Parquet 允许按列值对文件进行分区。对 parquet 文件进行分区时,将使用 parquet 文件的名称和列值的子文件夹创建顶级文件夹,然后这些子文件夹包含实际的 parquet 数据文件。例如 Hierarchy.parquet(文件夹)--> date=20220401(子文件夹)-->part1.parquet
预期行为
DuckDB 用于查询分区和未分区的 parquet 文件。
观察到的行为
DuckDB 在查询分区的 parquet 文件时失败,但可以处理未分区的 parquet 文件。
con.execute("Select * from 'Hierarchy.parquet'")
失败
RuntimeError: IO Error: No files found that match the pattern "Hierarchy.parquet"
当 Hierarchy.parquet 分区时。
查询底层个人数据文件工作正常:
con.execute("Select * from 'Hierarchy.parquet/date=20220401/part1.parquet'")
有没有办法用 DuckDB 查询分区的 parquet 文件?或者这是一个限制/错误?
这在
中作为 DuckDB 问题/功能请求进行讨论“支持镶木地板档案的蜂巢式分区” https://github.com/duckdb/duckdb/issues/2186。
建议的解决方法是:
import pyarrow.dataset as ds
import duckdb
con = duckdb.connect()
dataset = ds.dataset("Hierarchy.parquet", format="parquet", partitioning="hive")
con.register_arrow("Hierarchy", dataset)
con.execute("Select * from Hierarchy").df()
DuckDB 的直接支持会更好...但这工作正常并且很简单。
至少需要 DuckDB 0.4.1 才能支持分区 parquet 文件。
pip install -U --pre duckdb
例如,如果您的镶木地板按物种划分,
['/Users/steven/data/iris1/Species=setosa/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet',
'/Users/steven/data/iris1/Species=virginica/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet',
'/Users/steven/data/iris1/Species=versicolor/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet']
您可以这样查询,
select * from parquet_scan(['/Users/steven/data/iris1/Species=setosa/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet',
'/Users/steven/data/iris1/Species=virginica/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet',
'/Users/steven/data/iris1/Species=versicolor/0-06ea69fc-393b-4dc7-8940-46700d407ec4-0.parquet']
, HIVE_PARTITIONING=true);
参数
HIVE_PARTITIONING=true
非常重要。
我们的目标是双重的:
我创建了一个按州分区的城市数据的玩具 Parquet 数据集。源 csv 文件如下所示(总共 25 行):
rank,city,state,population,2000_2013_growth
1,New York,New York,8405837,4.8%
2,Los Angeles,California,3884307,4.8%
3,Chicago,Illinois,2718782,-6.1%
导入我需要的包:
import duckdb
import pandas as pd
import pyarrow.parquet as pq
我的第一个目标是将分区数据的子集转换为 DuckDB 可以查询的内容,在本例中是 Pandas 数据框:
parquet_file = f'{parquet_folder}/city_data.parquet'
filter_column = 'State'
states = ['California', 'Michigan', 'New York']
ds = pq.ParquetDataset(parquet_file, filters=[('state','in', states)])
df = ds.read().to_pandas()
接下来我将构建一个查询,一个简单的例子是:
query = """SELECT * FROM df WHERE State = 'California'"""
results_df = duckdb.query(query).to_df()
我刚刚开始使用 Parquet 和 DuckDB,所以我声称没有专业知识,这可能不是最好的方法。很高兴看到其他人添加他们的改进建议。