csv 形式のデータを DynamoDB に import したい

f:id:yrinda:20191120030055p:plain

どうも。いつもよりダイエット気分が高めな僕です。
パフォーマンス改善をするにはまず観測から...ということで、だいぶ前に wi-fi 接続できる体重計を購入し観測 & ロギングする作戦をすすめていました。しかしこの体重計、データがwithingsというサービスにストアされることになります。APIが公開されているものの、自分でデータを触ろうと思うと途端にめんどくさくなります。ということで自分がアクセスしやすいところにストアしてしまうことにしました。

  1. 過去のデータを一括で AWS DynamoDB に移行する。
  2. 今後のデータを 1日1回 withings API 経由で取得して、DynamoDB に反映する。

今回は 1. 過去データを DynamoDB に移行する をまとめた記事です。

やったこと

過去データを取得しよう

withings は親切なサービスで、画面ぽちぽちするだけで過去のデータを丸ごと csv export することができました。

日付,"体重 (kg)","体脂肪 (kg)","骨量 (kg)","筋肉量 (kg)","体水分率 (kg)",コメント
"2019-11-19 10:09:38",77.00,,,,,
"2019-11-18 22:54:40",78.20,,,,,
"2019-11-17 16:42:13",77.80,,,,,
"2019-11-13 15:45:27",77.40,,,,,
"2019-11-11 09:45:55",77.20,,,,,
"2019-11-07 10:06:58",77.00,,,,,
"2019-11-04 22:02:42",77.80,,,,,
"2019-10-30 08:32:27",78.00,,,,,
"2019-10-28 10:09:25",77.20,,,,,
...

最近体が重いなーと感じてましたが、物理的要因だったようです

DynamoDB に import したいのだが...

元ネタは取得できましたが、残念なことが発覚。DynamoDB に直接 csv を import することはできませんでした。ぱっと調べた感じで取りうる選択肢は3パターン。

  • S3 に cvs をアップロードして、AWS Data Pipeline を経由して import
  • AWS CLI を利用して import
  • AWS SDK を利用して import ( put_item のほうが正確かも)

どうやったか

デスクトップを作り替えたばかりでローカル環境がすっからかんでキレイな状態でした。そのため、環境整備もかねて AWS SDK を使うことにしました。よく見る Python + boto3 ( AWS SDK for Python ) の組み合わせです。内容は csv を読み込んで 1レコード毎に put_item する感じです。

やったこと一覧

※ローカル環境整備は除外

  1. DynamoDBに MyWeight テーブルを作成
    • csv を参照するとわかるように、有効な値がある列は日付体重 (kg)のみです。
      • 今回作るテーブルもデータにあわせて datetime, weight と最低限のカラムにしました。 f:id:yrinda:20191120023147p:plain
  2. csv header を日本語からカラム名に変更
    • 日付 -> datetime
    • 体重 (kg) -> weight
  3. csv の値がない列を削除
  4. AWS アクセスのため、IAM で DynamoDBのアクセス権限を付与したユーザを作成
    • めんどくさかったので一度のみの実行かつ、誤操作リスクも低かったため、 AmazonDynamoDBFullAccess を割り当てました。
  5. 適当に Pythonスクリプトをかきかき
  6. 実行
  7. 一時的に作成していたユーザを削除

結果

csv を DynamoDB に入れることができました。わーい🎉
これでデータがいじりやすくなりました。しかし、データを入れたとたん weight 列から重みを感じるようになりました。錯覚だとよいのですが (´-ω-`) f:id:yrinda:20191120024745p:plain

コード類

d.py

import boto3
import csv
import json

CSV_PATH = './weight.csv'
DYNAMO_TABLE_NAME = 'MyWeight'
ACCESS_KEY = 'xxxxxxxxxx'
SECRET_KEY = 'yyyyyyyyyyyyyyyyyyyyy'
REGION = 'xx-xxxxxxxx-x'


def main():
    session = boto3.Session(
        aws_access_key_id=ACCESS_KEY,
        aws_secret_access_key=SECRET_KEY,
        region_name=REGION
    )
    dynamo = session.resource('dynamodb')
    table = dynamo.Table(DYNAMO_TABLE_NAME)

    with open(CSV_PATH, 'r') as f:
        for r in csv.DictReader(f):
            j = json.loads(json.dumps(r))
            table.put_item(Item=j)


if __name__ == "__main__":
    main()

weight.csv

datetime,weight
"2019-11-19 10:09:38",77.00
"2019-11-18 22:54:40",78.20
"2019-11-17 16:42:13",77.80
"2019-11-13 15:45:27",77.40
"2019-11-11 09:45:55",77.20
"2019-11-07 10:06:58",77.00
"2019-11-04 22:02:42",77.80
"2019-10-30 08:32:27",78.00
"2019-10-28 10:09:25",77.20
...

余談

2. 今後のデータを 1日1回 withings API 経由で取得して、DynamoDB に反映する。 につづく...予定