2014-07-08 7 views
6

Ich benutze Boto S3 API in meinem Python-Skript, das langsam Daten von S3 in mein lokales Dateisystem kopiert. Das Skript funktionierte einige Tage lang gut, aber jetzt gibt es ein Problem.Boto S3 API gibt keine vollständige Schlüsselliste zurück

Ich verwende die Funktion folgenden API, um die Liste der Schlüssel in „Verzeichnis“ zu erhalten:

keys = bucket.get_all_keys(prefix=dirname) 

Und diese Funktion (get_all_keys) nicht immer die vollständige Liste des Schlüssels zurückgeben, ich meine, ich kann mehr sehen Schlüssel über die AWS-Weboberfläche oder über aws s3 ls s3://path.

Reproduziert das Problem auf Versionen 2.15 und 2.30.

Vielleicht cached Boto einige meiner Anfragen an S3 (ich wiederhole dieselben Anfragen immer und immer wieder)? Wie behebt man dieses Problem, irgendwelche Vorschläge?

Antwort

12

Es gibt einen einfacheren Weg. Das Bucket-Objekt selbst kann als Iterator fungieren und weiß, wie mit paginierten Antworten umgegangen wird. Wenn also mehr Ergebnisse verfügbar sind, werden sie automatisch im Hintergrund abgerufen. Also, so etwas wie dies sollte Ihnen ermöglichen, alle Objekte in dem Eimer iterieren:

for key in bucket: 
    # do something with your key 

Wenn Sie ein Präfix angeben möchten und eine Liste aller Schlüssel bekommen mit diesem Präfix beginnen, können Sie es tun, wie dies:

for key in bucket.list(prefix='foobar'): 
    # do something with your key 

Oder, wenn Sie wirklich wollen aufzubauen wirklich eine Liste von Objekten, gerade dies tun:

keys = [k for k in bucket] 

Beachten Sie jedoch, dass Eimer kann eine unbegrenzte Anzahl von Tasten halten, so sei vorsichtig l damit, weil es eine Liste aller Schlüssel im Speicher aufbaut.

+0

Wie Tasten mit bestimmtem Präfix zur Liste –

+1

aktualisierte einfach die Antwort mit einem Beispiel. – garnaat

5

Nur geschafft, es funktioniert zu bekommen! Es stellte sich heraus, dass ich 1013 Schlüssel in meinem Verzeichnis auf S3 hatte und get_all_keys nur 1000 Schlüssel aufgrund AWS API Einschränkungen zurückgeben kann.

Die Lösung ist einfach, benutzen Sie einfach mehr High-Level-Funktion ohne delimiter Parameter:

keys = list(bucket.list(prefix=dirname)) 
3

Sie müssen durch die Ergebnisse paginieren, indem Sie mehrere Anfragen stellen. list() wird dies automatisch für Sie tun. Sie können das folgende Beispiel für eine bessere Kontrolle oder zur Fortsetzung von fehlgeschlagenen Anfragen verwenden.

Dieser iterative Ansatz ist auch skalierbarer, wenn Sie Millionen von Objekten bearbeiten.

marker = None 
while True: 
    keys = bucket.get_all_keys(marker=marker) 
    last_key = None 

    for k in keys: 
     # TODO Do something with your keys! 
     last_key = k.name 

    if not keys.is_truncated: 
     break 

    marker = last_key 

Die ResultSet docs vom get_all_keys() docs sagen, dass dies autoamtically durch die für Iterator getan werden sollte, aber es funktioniert nicht. . :(

1

Verwenden Paginierung in boto3 sollte diese Funktion gibt Ihnen die Antwort:

def s3_list_files(bucket_name, prefix): 
    paginator = client.get_paginator("list_objects") 

    page_iterator = paginator.paginate(Bucket=bucket_name, Prefix=prefix) 
    keys = [] 
    for page in page_iterator: 
     if "Contents" in page: 
      for key in page["Contents"]: 
       keyString = key["Key"] 
       keys.append(keyString) 

    return keys if keys else []