はじめに
WorkatoのPythonコネクタを使って「既存のエクセルファイルの指定セルから、CSVデータを上書きする」という処理を実装していたところ、謎のエラーに遭遇しました。 ログを確認しても明確な記述はありませんでしたが、挙動からしてメモリ不足(Out of Memory) によるクラッシュと推測しました。
この記事では、Workatoのリソース制限の中で、どのようにExcelファイルの処理を最適化したか、その知見を共有します。
Workato Pythonコネクターの制限事項
制限事項まとめ
- 処理時間: 最大 90秒
- メモリ: 最大 256MB
- Pandasの推奨ファイルサイズ上限: Excelファイルの場合、5MB
Workato:Pythonコネクタの制限事項
https://qiita.com/tabimoba/items/790d4c2a382588221698
当初はデータ分析でおなじみの pandas を使って処理していました。しかし、一般的な仕様を調べると、以下の事実が判明しました。
- Pandasは内部的に openpyxl 等を使用しますが、データ構造を展開するため、ファイルサイズの約50倍のメモリを消費すると言われています。
つまり、5MBのExcelファイルを読み込むだけで 5MB × 50 = 250MB となり、Workatoのメモリ上限(256MB)を使い切ってしまう計算になります。
Openpyxlの read_only / write_only モード
Pandasは諦め、メモリ効率を最優先するために openpyxl を直接使用することにしました。 さらに、ファイルをすべてメモリに展開せず、ストリーム処理を行うために以下のモードを活用します。
- read_only: メモリ消費を抑えて読み込むモード
- write_only: メモリ消費を抑えて、新規ファイルを作成するモード
制限
- セル幅やヘッダー情報は読み取れない
- 書式設定(色・フォント)は自動コピーされない
write_only モードで新しいファイルを作る際、元のセルの値をコピーしただけでは、文字色・背景色・太字・罫線などは引き継げません。
書式を引き継ぐには、セルごとに属性(Font, Fill, Border, Alignmentなど)を読み取り、新しいセルオブジェクトにセットし直す実装が必要です。
実装アプローチ
メモリ節約のため以下の手順を踏みます。
1.新規作成: write_only モードで新しいWorkbookオブジェクトを作成。
2.転記: 既存のExcelを read_only で開き、行ごとに読み込んで、新しいWorkbookへ書き込む。
3.追記: 続いてCSVデータを読み込み、新しいWorkbookへ書き込む。
4.保存: ファイルを保存する。
以下を考慮しながらコードを書きました。
-
全ワークシートをコピー
read_onlyモードでもシート一覧は取得可能です。ループですべてのシートを巡回し、write_only 側のブックにコピーします。 -
書式設定の移植
write_only モードでは、単に値を渡すだけでは書式が消えます。セルごとに属性を個別にコピーします。
ベンチマーク結果
このアプローチに変更した結果、処理能力は以下のように変化しました。
- Pandas: 約1.7MBのExcelファイルでメモリ不足エラー
- Openpyxl: 約18MB のExcelファイル生成に成功
新たな問題:90秒の壁
メモリの問題はクリアし、扱えるファイルサイズは大幅に向上しました。しかし、ファイルサイズが18MBを超えたあたりから、今度は 「処理時間90秒」の制限に引っかかるようになりました。
これ以上のサイズを扱う場合は、ファイルを分割するか、Python以外の手段(WorkatoのCSVコネクタ機能など)などを検討する必要がありそうです。
まとめ
WorkatoのPythonコネクタでExcelを扱う際は、以下の点に注意が必要です。
- Pandas: メモリ効率が悪いため、256MB制限にすぐ抵触します。
- Openpyxl: read_only と write_only を組み合わせることで、メモリ消費を劇的に抑えられます。各制限に注意が必要です。
- 処理時間: メモリが足りても、90秒の壁があります。
同じようなエラーで困っている方の参考になれば幸いです。