PythonでCSVファイルをS3 SELECTする


概要

サンプルデータを準備

  • なんでもいいんですが、ちょっとした大きさのテストファイルを作成します
make_testfile.py
import hashlib

with open('testfile.csv', 'w') as f:
    for i in range(10000):
        f.write('{},{}\n'.format(i, hashlib.sha512(str(i).encode()).hexdigest()))
  • 連番+適当なハッシュ文字列の2カラム、1万行のファイルができます
  • ファイルサイズは1.3MB程度です
testfile.csv
0,31bca02094eb78126a517b206a88c73cfa9ec6f704c7030d18212cace820f025f00bf0ea68dbf3f3a5436ca63b53bf7bf80ad8d5de7d8359d0b7fed9dbc3ab99
1,4dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8db9dfe84c58b2b37b89903a740e1ee172da793a6e79d560e5f7f9bd058a12a280433ed6fa46510a
2,40b244112641dd78dd4f93b6c9190dd46e0099194d5a44257b7efad6ef9ff4683da1eda0244448cb343aa688f5d3efd7314dafe580ac0bcbf115aeca9e8dc114
(省略)
  • S3バケットへアップロードします
  • マネジメントコンソールからでもOKです
$ aws s3 cp testfile.csv s3://my-s3select/
upload: ./testfile.csv to s3://my-s3select/testfile.csv

SELECTするコード

  • 返される結果は65000バイトに分割されるようです
  • 結果の意味にかかわらずブツ切りにされるので、一旦全体を受け取って結合して使用する必要がありそうです
  • ここではローカルファイルとして出力します
    • 実際はtempfileを使う感じかなと思います
    • 巨大にならない場面ならメモリ上で処理するかも
s3select.py
import boto3

s3 = boto3.client('s3')
response = s3.select_object_content(
    Bucket='my-s3select',
    Key='testfile.csv',
    ExpressionType='SQL',
    RequestProgress={'Enabled': True},
    Expression="SELECT * FROM S3Object",
    InputSerialization={'CSV': {}},
    OutputSerialization={'CSV': {}},
)

end_event_received = False
with open('output.csv', 'wb') as f:
    for event in response['Payload']:
        if 'Records' in event:
            f.write(event['Records']['Payload'])
        elif 'End' in event:
            end_event_received = True
if not end_event_received:
    raise Exception('処理が不完全です')

# あとはoutput.csvを開き直して処理する