こんにちは、AWS担当のwakです。
さて最近はMongoDBとお友達になりつつあったのですが、「AWS担当の」と言いつつDynamoDBを全く触っていないというのは良くないのではないかと思い始めました。皆様ご存知の通り、DynamoDBはAWSの提供するNoSQLデータベースサービスで、
- フルマネージド:難しいことはAWSが引き受けてくれる
- 安定性:膨大な量のサイズのデータを格納しても自動的にシャーディングが行われ(しかもオンラインで)、レイテンシは変わらない
- JSONドキュメントをそのまま格納できる
- 高可用性:自動的に3拠点間で多重化される
といった特徴を持つ、まさにクラウドの申し子のような代物です。また個人的には無料利用枠が割と大きめなのが重要な点で、巨大というには程遠く、手で管理するには大きすぎるJSONデータをカジュアルに管理するため、MongoDBの代わりに利用する選択肢になり得ます。今回はPowerShellでこのDynamoDBを触る方法について説明します。
猫キャッチャー
サンプルコード
まず最初に完全な形のサンプルコードを示します。
Add-Type -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSSDK.Core.dll" Add-Type -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSSDK.DynamoDBv2.dll" $accessKey = "********************"; $secretAccessKey = "****************************************"; $endPoint = [Amazon.RegionEndpoint]::APNortheast1; $client = New-Object Amazon.DynamoDBv2.AmazonDynamoDBClient($accessKey, $secretAccessKey, $endPoint); $tableName = "YOUR-TABLE-NAME" # 自分で作ったテーブル名 $table = [Amazon.DynamoDBv2.DocumentModel.Table]::LoadTable($client, $tableName); $document = [Amazon.DynamoDBv2.DocumentModel.Document]::FromJson('{...}') # 引数はJSON形式のテキスト $table.PutItem($document)
前提条件は以下の通りです。
- DynamoDBでテーブルを作成してあること
- IAMユーザーを作成し、適切な権限が割り当ててあること
- IAMユーザーのAPIキーを作成してあること
- AWS Tools for Windows PowerShellがインストール済みであること
- PowerShell 3.0以上
以下はこのコードの説明です。
DLLを直接読み込めば大抵のことはできる
上述の AWS Tools for Windows PowerShell をインストールすると、自動的に環境変数PSModulePath
*1へSDKのパスが追加され、特に何かを意識しなくてもGet-EC2Instance
やStart-EC2Instance
といったAWSのためのコマンドレットが使えるようになります。しかしリファレンスを参照すると分かるように、現時点では項目の追加・削除・編集のためのコマンドレットは用意されていません。そのためには(上のコードのように)直接SDKの中のコードを呼び出す必要があります。
そんなときはAdd-Type
で直接DLLを読み込んでしまいましょう。
PS C:\> [Amazon.RegionEndPoint]::APNortheast1 型 [Amazon.RegionEndPoint] が見つかりません。この型を含むアセンブリが読み込まれていることを確認してください。 発生場所 行:1 文字:1 + [Amazon.RegionEndPoint]::APNortheast1 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (Amazon.RegionEndPoint:TypeName) []、RuntimeException + FullyQualifiedErrorId : TypeNotFound PS C:\> Add-Type -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSSDK.Core.dll" PS C:\> [Amazon.RegionEndPoint]::APNortheast1 SystemName DisplayName ---------- ----------- ap-northeast-1 Asia Pacific (Tokyo)
このようにアセンブリが直接ロードできて使えるようになります。
DynamoDBの準備をする
まずDynamoDBのテーブルを作成します。パーティーションキー、ソートキーを適当に設定しました。なお、このキーは1度作ったらもう変更できません(変えたければテーブルを作り直して移行する必要があります)。
これができたら、このテーブルを触る権限を持ったIAMユーザーを準備し、APIキーを取得しておきます。
レコードを登録・更新・削除する
新規登録
まず空のテーブルへレコードを実際に登録してみます。レコードをまずPowerShellの連想配列@{Key1=値1; Key2=値2; ...}
で作成し、JSON形式のテキストを介してAmazon.DynamoDBv2.DocumentModel.DynamoDBEntry
クラスのインスタンスに変換してからDynamoDBへ送信しています。
# 投入するデータ $source = @( @{name = "Tama"; timestamp = "2015-12-04T00:00:00.000Z"; cuteness = 90; mood = "暇"}, @{name = "Tama"; timestamp = "2015-12-04T01:00:00.000Z"; cuteness = 100; mood = "とても暇"}, @{name = "Tama"; timestamp = "2015-12-04T02:00:00.000Z"; cuteness = "INF"; mood = "睡眠"}, @{name = "Wak"; timestamp = "2015-12-04T00:00:00.000Z"; cuteness = 0; mood = "腹減った"; memo = "ラーメン" }) $source | % { $json = $_ | ConvertTo-Json -Compress $document = [Amazon.DynamoDBv2.DocumentModel.Document]::FromJson($json) $table.PutItem($document) }
登録結果はManagement Consoleから確認することができます。cuteness
の型は数値だったり文字列だったり、memo
はあったりなかったりしますが、それでもDynamoDBは柔軟に受け入れてくれています。
更新する
テーブルを作るときに決めたキー(ここではname
とtimestamp
)が両方とも完全に一致するレコードを登録すると更新になります。つまりPutItem
はSQLのINSERT文ではなくMERGE/UPSERT文に相当するわけです。したがって次のコードはデータ部分以外は上と同じです。memo
に入れ子にした連想配列をセットしてみました。
$source = @( @{name = "Tama"; timestamp = "2015-12-04T02:00:00.000Z"; cuteness = "INF"; mood = "睡眠"; memo = "あおむけ"}, # 更新 @{name = "Tama"; timestamp = "2015-12-04T03:00:00.000Z"; cuteness = 100; mood = "ごはん"; memo = @{menu = "高級かりかり"; ammount = 2 }}) $source | % { $json = $_ | ConvertTo-Json -Compress $document = [Amazon.DynamoDBv2.DocumentModel.Document]::FromJson($json) $table.PutItem($document) }
1行は更新、1行は新規追加になりました。memo
カラムにはJSONが生で書いてあるように見えますが、よく見ると"N"
や"S"
といった見覚えのないキーが出てきています。これはDynamoDBが自動的に与えた型情報です。こちらもきちんと入れ子構造を持ったドキュメントとして管理されている証だと思ってください。
削除
ついでに削除も試しておきます。こちらも構文はまったく同じで、とにかくキーを指定してレコードを特定できればそれが処理対象になると考えればいいです。
$removed = @{name = "Wak"; timestamp = "2015-12-04T00:00:00.000Z"} | ConvertTo-JSON -Compress $document = [Amazon.DynamoDBv2.DocumentModel.Document]::FromJson($removed) $table.DeleteItem($document)
レコードを検索する
次は検索を行います。検索に相当するコマンドレットも用意されていないので、やはりこちらもSDKを直接呼び出します。たとえば SELECT * FROM helloDynamoDB WHERE cuteness > 80
に相当するスキャン*2なら、カラム名、演算子、値を順に指定して
$scanFilter = New-Object Amazon.DynamoDBv2.DocumentModel.ScanFilter $scanFilter.AddCondition("cuteness", [Amazon.DynamoDBv2.DocumentModel.ScanOperator]::GreaterThan, 80) $search = $table.Scan($scanFilter)
で検索ができます。この時点で得られる$search
はカーソルのようなもので、実際の結果はGetNextSet()
を呼び出して取得します(カーソルとは違って1件ずつではなく、最大1MB分のデータがまとめて返されます)。
PS C:\> $search = $table.Scan($scanFilter) PS C:\> $documentList = $search.GetNextSet() PS C:\> $documentList Key Value --- ----- timestamp 2015-12-04T00:00:00.000Z mood 暇 name Tama cuteness 90 timestamp 2015-12-04T01:00:00.000Z mood とても暇 name Tama cuteness 100
確かに2件の結果が取得できました。
実際の用途
今回はPowerShellからDynamoDBを利用する方法について書きました。次回はAWS ConfigのログをDynamoDBに格納し、PowerShellから検索して変更履歴を出力するという(多少は)実用的な用途に使ってみたいと思います。お楽しみに!
*1:ここで指定されたパスに配置されたモジュールは自動的に読み込まれるようになります。環境変数PATHのPowerShell版だと思えばだいたい合っています
*2:インデックスを使わないテーブルスキャンのようなものだと考えてください。したがって低速ですがすべての項目が検索対象に指定できます。テーブル作成時に指定したnameを使う検索なら、「スキャン」ではなく高速な「クエリ」が利用できます