使用 boto3 通过与特定文件名匹配的 S3 对象分页

Page through S3 objects matching specific filename using boto3

我有一个名为 /photos 的带前缀(或 "folder")的 AWS S3 存储桶。 "contains" 一堆图像文件和更少的 EVENT.json 个文件。一个天真的表示可能是这样的:

EVENT.json 文件有一个对象,该对象包含对任意数量图像文件的路径引用,这些图像文件将图像分组到特定事件中。使用上面的示例,image1.jpg 和 image2.jpg 可能出现在 1_EVENT.json 中,而 image3.jpg 可能属于 2_EVENT.json.

随着存储桶变大,我有兴趣对结果进行分页。我只想一次从 S3 请求一个页面,因为我需要它们。我 运行 遇到的问题是我想通过包含单词 "EVENT" 的键进行专门的分页。如果不带回所有对象然后过滤或迭代结果,我发现这很难完成。

使用 S3 Paginator,我可以进行寻呼。假设我的 PageSizeMaxItems 设置为 6,这就是我第一页返回的内容:

/photos/
/photos/image1.jpg
/photos/image2.jpg
/photos/1_EVENT.json
/photos/image3.jpg
/photos/2_EVENT.json

S3的扁平化结构意味着它根据Prefix对bucket中的所有对象进行分页,并根据分页参数进行限制和分页。这意味着我可以轻松获得多个 EVENT.json 个文件,或者 none 个文件,具体取决于页面。

所以我正在寻找更多类似的东西:

/photos/1_EVENT.json
/photos/2_EVENT.json
/photos/3_EVENT.json
/photos/4_EVENT.json
/photos/5_EVENT.json
/photos/6_EVENT.json

无需首先请求所有对象,然后以某种方式对结果集进行切片;这正是我目前正在做的事情:

client = boto3.client('s3')
paginator = client.get_paginator('list_objects_v2')
page_iterator = paginator.paginate(
    Bucket=app.config.get('S3_BUCKET'),
    Prefix="photos/")  # Left PaginationConfig MaxItems & PageSize off intentionally
filtered_iterator = page_iterator.search(
    "Contents[?contains(Key, `EVENT`)][]")
for page in filtered_iterator:
    # Do stuff.
    pass

上面的代码非常昂贵,没有分页,但它确实为我提供了包含我的 "EVENT" 搜索字符串的所有文件的列表。

我特别想使用 boto3 通过 S3 分页 EVENT.json 对象的结果,而无需在每次请求时返回和过滤所有对象的开销。这可能吗?

编辑:我已经将请求范围缩小到仅具有 photos/ 前缀的对象。这是因为我的存储桶中还有其他 "folders" 也可能包含 EVENT 文件。这阻止我使用 EVENT 或 EVENT.json 作为我的前缀,因为响应可能被其他文件夹中的文件污染。

最简单的方法是重新散列文件名结构,使 EVENT 文件遵循模式 photos/EVENT_*.json 而不是 photos/*_EVENT.json。然后你可以使用 photos/EVENT.

的通用前缀

除此之外,我认为您使用的昂贵方法实际上是解决此问题的唯一方法。

有一个前缀选项,您可以在 boto 的搜索功能之一上使用。这将大大减少它必须扫描的文件数量。但是,如果您最后必须在字符串中间使用通配符搜索字符串,我知道它必须扫描存储桶中的所有对象,那么您将不得不通过这些对象进行通配符搜索。

例如:

bucket.search_function(prefix="string")

不过我记不起 boto 函数了。