こんにちは。フューチャー株式会社TIG所属2020年新卒の大西です。
フューチャー Advent Calendar 2020 3日目を担当します。
現在業務でAWS(特にS3やGlue Jobなど)を使うことが多いのため、私自身の業務で躓いた経験を元に 「AWS初心者が躓きやすいポイントとその解消法」 というテーマでブログを書いていきます。
まず、今日扱うテーマは 「Boto3を用いた1,000件以上のS3オブジェクトの操作」 です。
躓きポイントの概要
Boto3はPythonを介してAWSを操作するためのライブラリです。
Boto3を用いてAWSを操作する方は、 list_objects_v2
や objects.filter
等の関数を使って複数のオブジェクトを取得する機会があるのではないでしょうか。
list_object_v2
をもちいたオブジェクトの取得例
import boto3
s3 = boto3.resource("s3")
bucket = s3.Bucket(bucket_name)
prefix = "S3バケットへのパス"
objects = bucket.meta.client.list_objects_v2(Bucket=bucket.name, Prefix=prefix)
しかし、上記の関数には 「一度のリクエストで取得できるオブジェクトの数は1,000件まで」 というルールがあり、1001件目以降のオブジェクトは取得することができません。
Boto3の公式ドキュメント内のS3に関する記述部分を読むと、S3では下記の関数に同様のルールが存在しているようです。
- get_bucket_replication()
- list_bucket_analytics_configurations()
- list_bucket_inventory_configurations()
- list_bucket_metrics_configurations()
- list_multipart_uploads()
- list_object_versions()
- list_objects()
- list_objects_v2()
- list_parts()
- put_bucket_analytics_configuration()
- put_bucket_inventory_configuration()
- put_bucket_lifecycle_configuration()
- put_bucket_metrics_configuration()
- put_bucket_replication()
- object_versions.filter()
- objects.filter()
- BucketLifecycleConfiguration.put()
解決方法
今回は例として list_objects_v2
を用いる場合の解決方法を書きます。
list_objects_v2の返り値のdictには、結果が切り捨てられているかどうかを示す IsTruncated
が含まれています。
そして、取得するオブジェクト数の上限を指定せずlist_objects_v2
を実行し、取得したオブジェクトの数が1000件を超えていた場合は、objects["IsTruncated"]
にTrueがセットされて返ってきます。
また、list_objects_v2は引数のStartAfter
を設定することで、指定したS3ファイルの次のファイルからオブジェクトを取得してくれます。
よって、objects["IsTruncated"]==True
だった場合は、1000件目のS3キーをStartAfterに設定して再度list_objects_v2を実行するという処理を["IsTruncated"]==False
になるまで繰り返すことで、1,000件以上のオブジェクトでも取得することができます。
ソース
s3 = boto3.resource("s3")
bucket = s3.Bucket(source_bucket)
prefix = "S3バケットへのパス"
keys = get_all_keys(bucket.name, prefix, [], "")
def get_all_keys(bucket_name: str, prefix: str, keys: List[str], marker: str) -> List[str]:
"""
S3の指定したパスに存在するオブジェクトのキーを全て取得する
Parameters
----------
bucket_name: String
対象のBucket
prefix: String
対象のディレクトリのパス
keys: List[str]
marker: String
関数の中から呼び出す時のための引数。通常はkeys = [], marker = "" で呼び出す
Returns
-------
List[str]
取得したキーのリスト
"""
s3 = boto3.resource("s3")
bucket = s3.Bucket(bucket_name)
objects = bucket.meta.client.list_objects_v2(Bucket=bucket.name, Prefix=prefix, StartAfter=marker)
if "Contents" in objects:
keys.extend([content["Key"] for content in objects["Contents"]])
# 返り値のIsTruncatedがTrueかどうかを確認する
if objects.get("isTruncated"):
# marker引数に取得したkeysの末尾の値を設定して再度get_all_keysを実行する
return get_all_keys(bucket_name=bucket_name, prefix=prefix, keys=keys, marker=keys[-1])
return keys
最後に
今回は 「AWS初心者が躓きやすいポイントとその解消法」 の第一弾として IsTruncated
を用いた1,000件上限の解決についてまとめました。
大量のオブジェクトを一度に取得したい方はぜひ参考にしてみてください。