【问题标题】:Page through S3 objects matching specific filename using boto3使用 boto3 浏览与特定文件名匹配的 S3 对象
【发布时间】:2016-12-29 05:18:52
【问题描述】:

我有一个 AWS S3 存储桶,其前缀(或“文件夹”)称为 /photos。它“包含”一堆图像文件,甚至更少的EVENT.json 文件。一个幼稚的表示可能如下所示:

  • 我的真棒事件桶
    • 照片
      • image1.jpg
      • image2.jpg
      • 1_EVENT.json
      • image3.jpg
      • 2_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 文件,或者根本没有,具体取决于页面。

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

/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”搜索字符串的所有文件的列表。

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

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

【问题讨论】:

  • 如果您只需要 Amazon S3 内容列表并且不需要它完全最新,您可以使用 Amazon S3 Storage Inventory 将所有文件的每日 CSV 存储在您的 S3 存储桶中。
  • @JohnRotenstein Storage Inventory 似乎没有提供任何有助于分页结果的额外结构,并且仅限于根据 documentation 的前缀进行编目。但是,如果我可以使用它来创建和维护仅包含给定前缀的 EVENT 文件的清单,那么计划的清单可能值得等待。

标签: python amazon-web-services amazon-s3 paging boto3


【解决方案1】:

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

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

【讨论】:

  • 请使用`backticks` 转义文件名; *something between here* 呈现为斜体文本。
  • 不幸的是,文件名是由我进入项目之前开发的应用程序生成的。它已经在客户流通中,并且很难改变。在研究了一段时间后,我得出的结论是,我要么需要按照您的建议更改我们命名和组织文件的方式,要么解决带回所有对象的开销。我不应该感到惊讶,因为“简单”是以 S3 服务的名义出现的。我正在研究通过 RDS 缓存和分页结果。
【解决方案2】:

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

例如:

bucket.search_function(prefix="string")

不过,我记不起 boto 函数了。

【讨论】:

  • 不幸的是,我已经使用前缀将我的结果限制在 /photos“文件夹”中,否则我会使用 EVENT 作为前缀并称之为一天。不幸的是,在同一个存储桶中的其他“文件夹”中也有 EVENT 文件,我想防止它们污染我的 /photos 事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 1970-01-01
相关资源
最近更新 更多