2017-07-11 25 views
6

Tôi có cách hacky để đạt được điều này bằng cách sử dụng boto3 (1.4.4), pyarrow (0.4.1) và pandas (0.20.3).Làm thế nào để đọc một danh sách các tập tin gỗ từ S3 như một khung dữ liệu gấu trúc bằng cách sử dụng pyarrow?

Thứ nhất, tôi có thể đọc một file gỗ đơn tại địa phương như thế này:

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

tôi cũng có thể đọc một thư mục của file gỗ tại địa phương như thế này:

import pyarrow.parquet as pq 

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

Cả hai công việc giống như một nét duyên dáng. Bây giờ tôi muốn đạt được cùng một từ xa với các tập tin được lưu trữ trong một thùng S3. Tôi đã hy vọng rằng một cái gì đó như thế này sẽ làm việc:

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

Nhưng nó không:

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

Sau khi đọc pyarrow's documentation triệt để, điều này dường như không thể at the moment. Vì vậy, tôi bước ra với các giải pháp sau đây:

Đọc một tập tin duy nhất từ ​​S3 và nhận được một dataframe gấu trúc:

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

Và đây tôi hacky, không quá tối ưu hóa, giải pháp để tạo ra một dataframe gấu trúc từ đường dẫn thư mục 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) 

Có cách nào tốt hơn để đạt được điều này không? Có lẽ một số loại kết nối cho gấu trúc bằng cách sử dụng pyarrow? Tôi muốn tránh sử dụng pyspark, nhưng nếu không có giải pháp nào khác, thì tôi sẽ lấy nó.

+0

Bạn đã cân nhắc đọc chúng bằng dấu chấm chưa? Tôi có thể làm tương tự trong hai dòng. – user32185

Trả lời

2

Bạn có thể sử dụng s3fs từ dask thực hiện giao diện hệ thống tập tin cho s3. Sau đó, bạn có thể dùng tham số hệ thống tập tin của ParquetDataset như vậy:

import s3fs 
s3 = s3fs.S3FileSystem() 
dataset = pq.ParquetDataset('s3n://dsn/to/my/bucket', filesystem=s3) 
2

Bạn nên sử dụng các mô-đun s3fs theo đề nghị của yjk21. Tuy nhiên, kết quả của việc gọi ParquetDataset bạn sẽ nhận được một đối tượng pyarrow.parquet.ParquetDataset. Để có được Khung dữ liệu Pandas, bạn sẽ muốn áp dụng .read_pandas().to_pandas() cho nó:

import pyarrow.parquet as pq 
import s3fs 
s3 = s3fs.S3FileSystem() 

pandas_dataframe = pq.ParquetDataset('s3://your-bucket/', filesystem=s3).read_pandas().to_pandas() 
Các vấn đề liên quan