Comment lire une liste de parquet fichiers à partir de S3 comme les pandas dataframe à l'aide de pyarrow?

J'ai un hacky façon de réaliser cela à l'aide de boto3 (1.4.4), pyarrow (0.4.1) et pandas (0.20.3).

Tout d'abord, je peux lire un seul parquet fichier localement comme ceci:

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()

Je peux aussi lire un répertoire de parquet localement les fichiers comme ceci:

import pyarrow.parquet as pq

dataset = pq.ParquetDataset('parquet/')
table = dataset.read()
df = table.to_pandas()

À la fois le travail comme un charme. Maintenant, je veux atteindre le même à distance aux fichiers stockés dans un compartiment S3. J'espérais que quelque chose de ce genre:

dataset = pq.ParquetDataset('s3n://dsn/to/my/bucket')

Mais il ne le fait pas:

OSError: Passed non-file path: s3n://dsn/to/my/bucket

Après la lecture de pyarrow de la documentation à fond, cela ne semble pas possible pour le moment. Alors je suis venu avec la solution suivante:

Lecture d'un fichier unique à partir de S3 et de l'obtention des pandas dataframe:

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()

Et voici mon hacky, de ne pas très optimisé, la solution pour créer une pandas dataframe à partir d'un S3 chemin d'accès au dossier:

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)

Est-il un meilleur moyen pour y parvenir? Peut-être une sorte de connecteur pour les pandas à l'aide de pyarrow? Je voudrais éviter d'utiliser pyspark, mais si il n'y a pas d'autre solution, alors je le prendrais.

Avez-vous envisager de les lire avec dask? Je suis capable de faire la même dans les deux lignes.

OriginalL'auteur Diego Mora Cespedes | 2017-07-11