提问者:小点点

创建Parquet文件从流在python在内存效率的方式


Python创建Parquet文件的最常见方法似乎是首先创建一个熊猫数据帧,然后使用pyarrow将表写入parquet。我担心这可能会对内存使用造成过度负担——因为它需要至少一个数据集的完整副本存储在内存中才能创建熊猫数据帧。

我想知道是否由于列式压缩要求而需要将整个数据集加载到内存中,或者是否有更高效和基于流的方法。在我的例子中,我会以流式方式接收记录。对于类似的csv输出过程,我们以1000为批次将行写入磁盘,因此需要在内存中保存的行数永远不会达到完整数据集的大小。

我应该…?:

  1. 只需创建一个熊猫数据帧,然后将其写入parque。(这意味着整个数据集需要存储在内存中,但我们将此视为必要的要求。)
  2. 使用一些流式友好的方式在我们收到它们时一次写入1000行左右,最大限度地减少整个过程中的总时间点内存消耗。(我没有看到任何关于如何做到这一点的留档,我甚至不确定它是否是拼花的一个选项。)
  3. 将所有内容写入CSV,然后使用一个函数来智能地读取/分析CSV内容,并在事后创建压缩的拼花。(也许运行时间更慢,但内存配置文件更低,在非常大的文件上失败的机会更低。)

想法?建议?


共2个答案

匿名用户

使用一些流式友好的方式在我们收到它们时一次写入1000行左右,从而最大限度地减少整个过程中的总时间点内存消耗。

你可以做到这一点。

(我没有看到任何关于如何做到这一点的留档,我不确定这是否是拼花地板的一个选择。)

至少现在https://arrow.apache.org/docs/python/generated/pyarrow.parquet.ParquetWriter.html有一些关于如何做到这一点的留档-特别是write_batch函数

这是一个示例,尽管它必须根据数据源进行一些调整。例如,如果if已经出现“分块”,或者如果模式必须从数据中推断出来,而不是像这里那样硬编码。

该示例还通过Pandas进行,主要是因为它是一种从行转换为列以创建每个RecordBatch的便捷方式,但还有其他不需要熊猫的创建每个RecordBatch的方法。

import itertools
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq

# Any iterable that yields rows as tuples
def get_rows():
    for i in range(0, 10000):
        yield (1, 2)

# Chunk the rows into arrow batches
def get_batches(rows_iterable, chunk_size, schema):
    rows_it = iter(rows_iterable)
    while True:
        batch = pa.RecordBatch.from_pandas(
            pd.DataFrame(itertools.islice(rows_it, chunk_size), columns=schema.names),
            schema=schema, preserve_index=False,
        )
        if not batch:
            break
        yield batch

# Could be inferred from data, but note that the schema has to be
# known when creating the ParquetWriter object
schema = pa.schema([
    ('a', pa.int32()),
    ('b', pa.int32()),
])
rows = get_rows()
batches = get_batches(rows, chunk_size=1000, schema=schema)

# Write the batches
with pq.ParquetWriter('example.parquet', schema=schema) as writer:
    for batch in batches:
        writer.write_batch(batch)

匿名用户

您希望在Parquet中使用行组。请参阅此处了解它们的解释,但简短的版本是列式数据仅限于多行的块,每个块都可以单独附加到文件中。您可以使用PyArrow为传入数据流实现这一点。