web-dev-qa-db-fra.com

Importer un fichier CSV ou JSON dans DynamoDB

J'ai 1000 fichiers CSV. Chaque fichier CSV est compris entre 1 et 500 Mo et est formaté de la même manière (c'est-à-dire le même ordre de colonne). J'ai un fichier d'en-tête pour les en-têtes de colonne, qui correspondent aux noms de colonne de ma table DynamoDB. J'ai besoin d'importer ces fichiers dans une table DynamoDB. Quel est le meilleur moyen/outil pour le faire?

Je peux concaténer ces fichiers CSV en un seul fichier géant (je préfère cependant éviter de le faire), ou les convertir en JSON si nécessaire. Je suis conscient de l'existence de BatchWriteItem donc je suppose qu'une bonne solution impliquerait l'écriture par lots.


Exemple:

  • La table DynamoDB comporte deux colonnes: prénom, nom
  • Le fichier d'en-tête contient uniquement: first_name,last_name
  • Un fichier CSV ressemble

:

John,Doe
Bob,Smith
Alice,Lee
Foo,Bar
7
Franck Dernoncourt

À la fin, j'ai codé une Python fonction import_csv_to_dynamodb(table_name, csv_file_name, colunm_names, column_types) qui importe un CSV dans une table DynamoDB. Les noms de colonne et la colonne doivent être spécifiés. Il utilise boto =, et s'inspire beaucoup de cela Gist . Ci-dessous se trouve la fonction ainsi qu'une démo (main()) et le fichier CSV utilisé. Testé sur Windows 7 x64 avec = Python 2.7.5, mais cela devrait fonctionner sur n'importe quel OS qui a boto et Python.

import boto

MY_ACCESS_KEY_ID = 'copy your access key ID here'
MY_SECRET_ACCESS_KEY = 'copy your secrete access key here'


def do_batch_write(items, table_name, dynamodb_table, dynamodb_conn):
    '''
    From https://Gist.github.com/griggheo/2698152#file-gistfile1-py-L31
    '''
    batch_list = dynamodb_conn.new_batch_write_list()
    batch_list.add_batch(dynamodb_table, puts=items)
    while True:
        response = dynamodb_conn.batch_write_item(batch_list)
        unprocessed = response.get('UnprocessedItems', None)
        if not unprocessed:
            break
        batch_list = dynamodb_conn.new_batch_write_list()
        unprocessed_list = unprocessed[table_name]
        items = []
        for u in unprocessed_list:
            item_attr = u['PutRequest']['Item']
            item = dynamodb_table.new_item(
                    attrs=item_attr
            )
            items.append(item)
        batch_list.add_batch(dynamodb_table, puts=items)


def import_csv_to_dynamodb(table_name, csv_file_name, colunm_names, column_types):
    '''
    Import a CSV file to a DynamoDB table
    '''        
    dynamodb_conn = boto.connect_dynamodb(aws_access_key_id=MY_ACCESS_KEY_ID, aws_secret_access_key=MY_SECRET_ACCESS_KEY)
    dynamodb_table = dynamodb_conn.get_table(table_name)     
    BATCH_COUNT = 2 # 25 is the maximum batch size for Amazon DynamoDB

    items = []

    count = 0
    csv_file = open(csv_file_name, 'r')
    for cur_line in csv_file:
        count += 1
        cur_line = cur_line.strip().split(',')

        row = {}
        for colunm_number, colunm_name in enumerate(colunm_names):
            row[colunm_name] = column_types[colunm_number](cur_line[colunm_number])

        item = dynamodb_table.new_item(
                    attrs=row
            )           
        items.append(item)

        if count % BATCH_COUNT == 0:
            print 'batch write start ... ', 
            do_batch_write(items, table_name, dynamodb_table, dynamodb_conn)
            items = []
            print 'batch done! (row number: ' + str(count) + ')'

    # flush remaining items, if any
    if len(items) > 0: 
        do_batch_write(items, table_name, dynamodb_table, dynamodb_conn)


    csv_file.close() 


def main():
    '''
    Demonstration of the use of import_csv_to_dynamodb()
    We assume the existence of a table named `test_persons`, with
    - Last_name as primary hash key (type: string)
    - First_name as primary range key (type: string)
    '''
    colunm_names = 'Last_name First_name'.split()
    table_name = 'test_persons'
    csv_file_name = 'test.csv'
    column_types = [str, str]
    import_csv_to_dynamodb(table_name, csv_file_name, colunm_names, column_types)


if __name__ == "__main__":
    main()
    #cProfile.run('main()') # if you want to do some profiling

Contenu de test.csv (Doit se trouver dans le même dossier que le Python):

John,Doe
Bob,Smith
Alice,Lee
Foo,Bar
a,b
c,d
e,f
g,h
i,j
j,l
12
Franck Dernoncourt

Modifié légèrement la réponse précédente pour utiliser le module CSV afin que votre fichier CSV puisse prendre en charge les chaînes avec des guillemets.

import boto
from csv import reader

MY_ACCESS_KEY_ID = 'copy your access key ID here'
MY_SECRET_ACCESS_KEY = 'copy your secrete access key here'


def do_batch_write(items, table_name, dynamodb_table, dynamodb_conn):
    '''
    From https://Gist.github.com/griggheo/2698152#file-gistfile1-py-L31
    '''
    batch_list = dynamodb_conn.new_batch_write_list()
    batch_list.add_batch(dynamodb_table, puts=items)
    while True:
        response = dynamodb_conn.batch_write_item(batch_list)
        unprocessed = response.get('UnprocessedItems', None)
        if not unprocessed:
            break
        batch_list = dynamodb_conn.new_batch_write_list()
        unprocessed_list = unprocessed[table_name]
        items = []
        for u in unprocessed_list:
            item_attr = u['PutRequest']['Item']
            item = dynamodb_table.new_item(
                    attrs=item_attr
            )
            items.append(item)
        batch_list.add_batch(dynamodb_table, puts=items)


def import_csv_to_dynamodb(table_name, csv_file_name, colunm_names,     column_types):
    '''
    Import a CSV file to a DynamoDB table
    '''        
    dynamodb_conn =     boto.connect_dynamodb(aws_access_key_id=MY_ACCESS_KEY_ID, aws_secret_access_key=MY_SECRET_ACCESS_KEY)
    dynamodb_table = dynamodb_conn.get_table(table_name)     
    BATCH_COUNT = 2 # 25 is the maximum batch size for Amazon DynamoDB

    items = []

    count = 0
    csv_file = open(csv_file_name, 'r')
    for cur_line in reader(csv_file):
        count += 1

        row = {}
        for colunm_number, colunm_name in enumerate(colunm_names):
            row[colunm_name] = column_types[colunm_number]    (cur_line[colunm_number])

        item = dynamodb_table.new_item(
                    attrs=row
            )           
        items.append(item)

        if count % BATCH_COUNT == 0:
            print 'batch write start ... ', 
            do_batch_write(items, table_name, dynamodb_table, dynamodb_conn)
            items = []
            print 'batch done! (row number: ' + str(count) + ')'

    # flush remaining items, if any
    if len(items) > 0: 
        do_batch_write(items, table_name, dynamodb_table, dynamodb_conn)


    csv_file.close() 


def main():
    '''
    Demonstration of the use of import_csv_to_dynamodb()
    We assume the existence of a table named `test_persons`, with
    - Last_name as primary hash key (type: string)
    - First_name as primary range key (type: string)
    '''
    colunm_names = 'facebookID age ethnicity gender hometown name party sfw url'.split()
    table_name = 'OneAmericaDB'
    csv_file_name = 'test_data.csv'
    column_types = [str, str, str, str, str, str, str, str, str]
    import_csv_to_dynamodb(table_name, csv_file_name, colunm_names, column_types)


if __name__ == "__main__":
    main()
    #cProfile.run('main()') # if you want to do some profiling
0
John Tubert

Ce package NPM convertit un json arbitray en une demande PUT pour DynamoDB. https://www.npmjs.com/package/json-dynamo-putrequest

Vaut vraiment le coup.

0
tinker

Je vous suggère d'utiliser AWS Database Migration Service (DMS).

Comme décrit dans cet article: https://aws.Amazon.com/es/blogs/database/migrate-delimited-files-from-Amazon-s3-to-an-Amazon-dynamodb-nosql-table- using-aws-database-migration-service-and-aws-cloudformation / vous pouvez utiliser S3 comme origine et DynamoDB comme cible pour importer des fichiers csv avec beaucoup de tuples.

J'ai réussi à implémenter un processus d'importation complet de S3 vers DynamoDB et c'est le moyen le plus simple et le plus rapide de le faire.

Essentiellement, vous devez:

  • Ayez un compartiment dans lequel placer vos fichiers csv, avec au moins deux niveaux de dossiers (le premier renvoie au "schéma" et le second au "nom de la table").
  • Avoir une table DynamoDB avec au moins la même clé de hachage que dans les fichiers csv.
  • Créez un élément Origin dans DMS pointant vers S3 et mappant la structure csv.
  • Créez un élément cible dans DMS pointant vers la table DynamoDB et le mappage à partir de l'origine mappée.
  • Créez une instance de réplication (faites attention au niveau gratuit) dans DMS.
  • Créez une tâche de réplication dans DMS qui utilise les éléments créés d'origine et cible.
  • Exécutez la tâche.

En modifiant le débit de la table DynamoDB à 25 unités de capacité de lecture et 150 unités de capacité d'écriture, j'ai pu insérer plus de 124 000 tuples en moins de 7 minutes, y compris les tâches de préparation.

La principale recommandation d'AWS pour cette tâche est d'utiliser le service de pipeline de données, mais je l'ai utilisé et il est plus cher et l'initialisation sous-jacente de l'EMR est un processus très lent, donc si vous ne voulez pas répéter cette tâche d'importation, utilisez DMS de manière récurrente au lieu.