背景
Raspberry PiでEthernetから受信したデータをparquet変換してAmazon S3へアップロードするプログラムを書いていたとき、ローカルストレージを使用するとmicro SDカードの寿命が縮むのでメモリ上で処理するようにした時のメモ。
結論
pyarrow.parquet.write_table()などの引数にpyarrow.fs.S3FileSystemを指定するとメモリから直接Amazon S3に書き込める。
サンプルコード
import pyarrow.parquet
import pyarrow.fs
# 事前にmy_tableという変数でpyarrow.Tableを構築している前提
BucketName = "my_bucket"
objectkey = "objname/date=20250915/my_file.parquet"
my_region = "ap-northeast-1"
# proxyが必要な場合の設定例
my_proxy = {
"host" : "192.168.1.1",
"port" : "8080",
"username" : "",
"password" : ""
}
# S3に書き込み
pyarrow.parquet.write_table(
my_table, # sliceなど加工してもよい
f"{BucketName}/{objectkey}",
filesystem=pyarrow.fs.S3FileSystem(
region=my_region,
background_writes=False,
proxy_options=my_proxy
),
)
追記:Amazon Athenaによる低コスト可視化
オブジェクトキーに date=20250915 と日付を入れたのは、Glue Data Catalogを構築後にAthenaでパーティションキーを指定してS3に保存したデータファイルを検索させるため。
Athenaの読み取りデータ量を減らす方法
詳細はAWSのマニュアルをご覧ください。ここでは簡単な方法のみ触れます。
- 圧縮・列指向フォーマットのparquet形式でアップロード
SQLに列指定を入れる場合は当該列しか読まないparquetが効果的 - where句に適切なパーティションキーの値を指定して絞る
Glue Data Catalogでパーティションが正しく登録されていれば、指定したプリフィックス内のファイルしか読み取らない。
この例では WHERE date='20250915' と指定すると、2025年09月15日のフォルダ内のファイルだけを探して結果を返す。日付以外にも型番やシリアルなどアクセスパターンが既知であればそれをパーティションキーにすると良い。 - クラウド側でファイルを集約
細かいファイルを多数読み込むとS3の読み取りリクエスト課金が増えたり、スロットリングされるので、検索される時の粒度を優先しつつ1ファイル128MB〜256MB程度に集約する
パーティションの追加登録
パーティションの追加登録はクライアントからboto3のGlue.client.create_partition()で実行できるので、スキーマが変わらない限りGlue Crawlerを再実行する必要はない。初回のスキーマ構築はGlue Crawlerまたは手動のお好みの方法で。
パーティション射影
Partition Projection(パーティション射影)を使えば、Glue Data Catalogにパーティションを登録しなくてもAthenaだけはパーティションキーを使った検索が可能。Redshift SpectrumなどのAthena以外のシステムはGlue Data Catalogを経由してS3へアクセスするので、引き続きGlue Data Catalogの構築と保守が必要
将来的なIcebergテーブルへの移行
parquetでアップロードしておけば、上述のHiveスタイルのテーブルからIcebergテーブルへのインプレース移行が可能なので、将来的に行単位の処理をしたくなったりしてIcebergテーブルに乗り換えたくなった時もつぶしが効きそう。
CSVでアップロードすると、フルデータ移行しか実施できないため、可視化プロジェクトが上手くいってデータ量が増えるほど身動きが取れなくなる。
他のDWHへのデータロード
主要なデータウェアハウスはS3からのデータ取り込みをサポートしていることが多いので、S3に入れておけば何とかなることが期待できる。