You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效查询Parquet文件中排序列X小于指定值的最后一行Y值

高效查询已排序Parquet文件中X<指定值的最后一个Y值

问题背景

有一个大型Parquet文件,其中X列已按升序排序,示例数据如下:

X   Y
0   1   Red
1   5   Blue
2   8   Green
3   12  Purple
4   15  Blue
5   17  Purple

需要用Python以最高效的方式查询X小于指定值时Y列的最后一个值,例如查询X<11时预期得到"Green"。

已尝试以下代码:

columns='Y'
filters=[('X','<',11)]

pd.read_parquet('my_data.parquet',filters=filters,columns=columns).tail(1)

该代码可运行,但每日需执行100万+次查询,现有方案效率不足。文件过大无法载入内存,且X值间隔无规律,无法通过指定起始值缩小范围,希望借助X列已排序的特性优化,可使用DuckDB等其他库。

优化方案

方案1:使用DuckDB(推荐)

DuckDB对Parquet的列式存储和排序特性有很好的支持,能直接利用X的有序性快速定位目标行,避免全表扫描:

import duckdb

def get_last_y(target_x):
    conn = duckdb.connect()
    # 利用X升序特性,直接取最大的X<target_x对应的Y
    result = conn.execute(
        """
        SELECT Y 
        FROM 'my_data.parquet' 
        WHERE X < ? 
        ORDER BY X DESC 
        LIMIT 1
        """,
        [target_x]
    ).fetchone()
    conn.close()
    return result[0] if result else None

# 调用示例
print(get_last_y(11))  # 输出 Green

DuckDB会自动利用Parquet的统计信息(因X排序,文件/分区的min/max X已知)快速跳过不符合条件的分区,同时ORDER BY X DESC LIMIT 1不需要扫描所有符合条件的行,能直接定位到最后一个符合条件的记录。

方案2:使用PyArrow Dataset结合二分查找

PyArrow可以直接操作Parquet文件的元数据,结合X的有序性实现二分查找,避免全量读取:

import pyarrow.parquet as pq

def get_last_y_pyarrow(target_x):
    dataset = pq.ParquetDataset('my_data.parquet')
    fragments = dataset.fragments
    # 二分查找找到包含最大X<target_x的片段
    left, right = 0, len(fragments)-1
    candidate_fragment = None
    while left <= right:
        mid = (left + right) // 2
        fragment = fragments[mid]
        stats = fragment.metadata.row_group(0).statistics['X']
        if stats.max < target_x:
            candidate_fragment = fragment
            left = mid + 1
        else:
            right = mid - 1
    if not candidate_fragment:
        return None
    # 读取候选片段的X和Y列,找到最后一个X<target_x的Y
    table = candidate_fragment.to_table(columns=['X', 'Y'])
    x_arr = table['X'].to_numpy()
    idx = x_arr.searchsorted(target_x, side='right') - 1
    return table['Y'][idx].as_py() if idx >=0 else None

# 调用示例
print(get_last_y_pyarrow(11))  # 输出 Green

这个方法先通过片段的统计信息快速定位可能包含目标行的Parquet片段,再在片段内用二分查找找到具体行,大幅减少IO和计算量。

方案3:预建索引(超高频查询场景)

如果每日查询量超百万,可以预先为X列建立单独的索引文件(比如保存所有X值的数组和对应的Y值偏移),每次查询直接在索引数组上做二分查找,再通过偏移读取Parquet文件中对应的Y值。这种方法单次查询速度最快,但需要额外的存储空间和索引维护成本。

内容的提问来源于stack exchange,提问作者jd0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 08:10:22