web-dev-qa-db-ja.com

CSVまたはJSONファイルをDynamoDBにインポートする

1000個のCSVファイルがあります。各CSVファイルは1〜500 MBで、同じ方法でフォーマットされます(つまり、同じ列順)。 DynamoDBテーブルの列名と一致する列ヘッダーのヘッダーファイルがあります。これらのファイルをDynamoDBテーブルにインポートする必要があります。そうするための最良の方法/ツールは何ですか?

これらのCSVファイルを1つの巨大なファイルに連結する(ただし、避けたい)か、必要に応じてJSONに変換できます。 BatchWriteItem の存在を知っているので、良い方法はバッチ書き込みを伴うと思います。


例:

  • DynamoDBテーブルには、first_name、last_nameの2つの列があります。
  • ヘッダーファイルには以下のみが含まれます:first_name,last_name
  • 1つのCSVファイルは次のようになります

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

最後に、CSVをDynamoDBテーブルにインポートするPython function import_csv_to_dynamodb(table_name, csv_file_name, colunm_names, column_types)をコーディングしました。列名と列を指定する必要があります。これは boto を使用します=、そしてこれから多くのインスピレーションを得ます Gist 。以下は、関数とデモ(main())および使用されるCSVファイルです。Windows7 x64でテスト済み= Python 2.7.5。ただし、botoとPythonを備えたすべてのOSで動作するはずです。

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

test.csvのコンテンツ(Pythonスクリプト)と同じフォルダにある必要があります):

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

以前の回答を少し変更してCSVモジュールを使用するようにしたので、CSVファイルは引用符付きの文字列をサポートできます。

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

このNPMパッケージは、arbitray jsonをDynamoDBのPUTリクエストに変換します。 https://www.npmjs.com/package/json-dynamo-putrequest

間違いなく試してみる価値があります。

0
tinker

AWS Database Migration Service(DMS)を使用することをお勧めします。

この記事で説明されているように、 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 / S3をオリジンとして使用し、DynamoDBをターゲットとして使用して、多数のタプルを含むcsvファイルをインポートできます。

私は、S3からDynamoDBへの完全なインポートプロセスを正常に実装しました。これは、最も簡単で最速の方法です。

基本的に、次のことを行う必要があります。

  • Csvファイルを入れるバケットを用意し、少なくとも2つのフォルダーレベルを指定します(最初のフォルダーは「スキーマ」を参照し、2番目のフォルダーは「テーブル名」です)。
  • 少なくともcsvファイルと同じハッシュキーを持つDynamoDBテーブルを用意します。
  • S3をポイントし、csv構造をマッピングするOrigin要素をDMSに作成します。
  • DynamoDBテーブルをポイントし、マップされたOriginからマッピングするターゲット要素をDMSに作成します。
  • DMSでレプリケーションインスタンスを作成します(無料枠に注意してください)。
  • DMSで、Originとターゲットの作成された要素を使用するレプリケーションタスクを作成します。
  • タスクを実行します。

DynamoDBテーブルのスループットを25の読み取りキャパシティーユニットと150の書き込みキャパシティーユニットに変更すると、準備タスクを含めて、7分未満で124k以上のタプルを挿入できました。

このタスクのAWSの主な推奨事項は、データパイプラインサービスを使用することですが、私はこれを使用しており、コストが高く、基になるEMRカルスターの初期化は非常に遅いプロセスなので、このインポートタスクを繰り返したくない場合は、DMSを繰り返し使用します代わりに。