У меня есть хакерский способ достижения этого, используя boto3
(1.4.4), pyarrow
(0.4.1) и pandas
(0.20.3).
Во-первых, я могу прочитать один файл паркета локально следующим образом:
import pyarrow.parquet as pq
path = 'parquet/part-r-00000-1e638be4-e31f-498a-a359-47d017a0059c.gz.parquet'
table = pq.read_table(path)
df = table.to_pandas()
Я также могу локально локализовать каталог паркетных файлов следующим образом:
import pyarrow.parquet as pq
dataset = pq.ParquetDataset('parquet/')
table = dataset.read()
df = table.to_pandas()
Оба работают как обаяние. Теперь я хочу получить то же самое с файлами, хранящимися в ведре S3. Я надеялся, что что-то вроде этого будет работать:
dataset = pq.ParquetDataset('s3n://dsn/to/my/bucket')
Но это не так:
OSError: Passed non-file path: s3n://dsn/to/my/bucket
Прочитав документацию по pyarrow, это не представляется возможным на момент. Поэтому я вышел со следующим решением:
Чтение одного файла из S3 и получение фрейма pandas:
import io
import boto3
import pyarrow.parquet as pq
buffer = io.BytesIO()
s3 = boto3.resource('s3')
s3_object = s3.Object('bucket-name', 'key/to/parquet/file.gz.parquet')
s3_object.download_fileobj(buffer)
table = pq.read_table(buffer)
df = table.to_pandas()
И вот мое хакерское, не очень оптимизированное решение для создания pandas фрейма данных из пути папки S3:
import io
import boto3
import pandas as pd
import pyarrow.parquet as pq
bucket_name = 'bucket-name'
def download_s3_parquet_file(s3, bucket, key):
buffer = io.BytesIO()
s3.Object(bucket, key).download_fileobj(buffer)
return buffer
client = boto3.client('s3')
s3 = boto3.resource('s3')
objects_dict = client.list_objects_v2(Bucket=bucket_name, Prefix='my/folder/prefix')
s3_keys = [item['Key'] for item in objects_dict['Contents'] if item['Key'].endswith('.parquet')]
buffers = [download_s3_parquet_file(s3, bucket_name, key) for key in s3_keys]
dfs = [pq.read_table(buffer).to_pandas() for buffer in buffers]
df = pd.concat(dfs, ignore_index=True)
Есть ли лучший способ достичь этого? Может быть, какой-то разъем для pandas с использованием пиарроу? Я бы хотел избежать использования pyspark
, но если другого решения нет, тогда я бы взял его.