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:
first_name,last_name
:
John,Doe
Bob,Smith
Alice,Lee
Foo,Bar
À 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
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
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.
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:
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.