DynamoDBMapper クラス - Amazon DynamoDB

DynamoDBMapper クラス

DynamoDBMapper クラスは、Amazon DynamoDB のエントリポイントとなります。このクラスは、DynamoDB エンドポイントへのアクセスを提供し、さまざまなテーブルのデータを使用できるようにします。また、アイテムに対する作成、読み込み、更新、削除 (CRUD) の各オペレーションの実行、およびテーブルに対するクエリやスキャンを行うことができます。このクラスでは、DynamoDB を操作するために以下のメソッドが提供されます。

対応する Javadoc ドキュメントについては、AWS SDK for Java API リファレンスの「DynamoDBMapper」を参照してください。

save

指定したオブジェクトがテーブルに保存されます。このメソッドで必要なパラメータは、保存するオブジェクトだけです。DynamoDBMapperConfig オブジェクトを使用して、オプションの設定パラメータを入力できます。

同じプライマリキーを持つ項目が存在しない場合は、このメソッドによってテーブル内に新しい項目が作成されます。同じプライマリキーを持つ項目が存在する場合は、その既存の項目が更新されます。パーティションキーとソートキーが String 型で、@DynamoDBAutoGeneratedKey によって注釈が付けられている場合、初期化しなければ、ランダムな UUID (Universally Unique Identifier) が与えられます。@DynamoDBVersionAttribute で注釈が付けられたバージョンフィールドは、バージョンが 1 ずつ増えていきます。さらに、バージョンフィールドが更新されるかキーが生成されると、オペレーションの結果として、渡されたオブジェクトが更新されます。

デフォルトでは、マップされたクラスプロパティに対応する属性のみが更新されます。アイテムのその他の既存の属性には影響はありません。ただし、SaveBehavior.CLOBBER を指定すると、項目が完全に上書きされるようにすることができます。

DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER).build(); mapper.save(item, config);

バージョニングを有効にした場合は、クライアント側とサーバー側で項目のバージョンが一致する必要があります。ただし、SaveBehavior.CLOBBER オプションを使用する場合は、バージョンを一致させる必要はありません。バージョニングの詳細については、「DynamoDB およびバージョン番号を使用した楽観的ロック」を参照してください。

load

テーブルから項目を取り出します。取得する項目のプライマリキーを入力する必要があります。DynamoDBMapperConfig オブジェクトを使用して、オプションの設定パラメータを入力できます。たとえば次の Java ステートメントに示すように、オプションで強力な整合性のある読み込みをリクエストして、このメソッドによって最新の項目の値だけを取り出すようにすることができます。

DynamoDBMapperConfig config = DynamoDBMapperConfig.builder() .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT).build(); CatalogItem item = mapper.load(CatalogItem.class, item.getId(), config);

DynamoDB のデフォルトでは、結果整合性のある値を持つ項目が返されます。DynamoDB の結果整合性モデルの詳細については、「DynamoDB の読み取り整合性」を参照してください。

削除

テーブルから項目を削除します。マッピングされたクラスのオブジェクトインスタンスを渡す必要があります。

バージョニングを有効にした場合は、クライアント側とサーバー側で項目のバージョンが一致する必要があります。ただし、SaveBehavior.CLOBBER オプションを使用する場合は、バージョンを一致させる必要はありません。バージョニングの詳細については、「DynamoDB およびバージョン番号を使用した楽観的ロック」を参照してください。

query

テーブルまたはセカンダリインデックスをクエリする

フォーラムスレッドの返信を格納する Reply というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。Reply テーブルのプライマリキーは、Id および ReplyDateTime フィールドで構成されます。ここで、Id はプライマリキーのパーティションキー、ReplyDateTime はソートキーを表します。

Reply ( Id, ReplyDateTime, ... )

Reply クラスと、それに対応する DynamoDB 内の Reply テーブルの間で、マッピングを作成したとします。次の Java コードでは、DynamoDBMapper を使用して特定のスレッド件名に対する過去 2 週間のすべての返信を検索しています。

String forumName = "&DDB;"; String forumSubject = "&DDB; Thread 1"; String partitionKey = forumName + "#" + forumSubject; long twoWeeksAgoMilli = (new Date()).getTime() - (14L*24L*60L*60L*1000L); Date twoWeeksAgo = new Date(); twoWeeksAgo.setTime(twoWeeksAgoMilli); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String twoWeeksAgoStr = df.format(twoWeeksAgo); Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS(partitionKey)); eav.put(":v2",new AttributeValue().withS(twoWeeksAgoStr.toString())); DynamoDBQueryExpression<Reply> queryExpression = new DynamoDBQueryExpression<Reply>() .withKeyConditionExpression("Id = :v1 and ReplyDateTime > :v2") .withExpressionAttributeValues(eav); List<Reply> latestReplies = mapper.query(Reply.class, queryExpression);

このクエリでは、Reply オブジェクトのコレクションが返されます。

デフォルトでは、query メソッドによって、「遅延ロード」されたコレクションが返されます。最初に結果が 1 ページのみ返され、必要に応じて、さらに次ページを要求するサービス呼び出しが行われます。一致するすべての項目を取得するには、latestReplies コレクションを反復処理します。

コレクションで size() メソッドを呼び出すと、正確なカウントを提供するためにすべての結果がロードされます。これにより、プロビジョニングされたスループットが大量に消費され、非常に大きなテーブルでは JVM 内のすべてのメモリが消費されることさえあります。

インデックスにクエリを実行するには、最初にインデックスをマッパークラスとしてモデリングする必要があります。今、Reply テーブルに、PostedBy-Message-Index という名前のグローバルセカンダリインデックスが存在すると仮定します。このインデックスのパーティションキーは PostedBy キーで、ソートキーは Message です。インデックス内の項目のクラス定義は次のようになります。

@DynamoDBTable(tableName="Reply") public class PostedByMessage { private String postedBy; private String message; @DynamoDBIndexHashKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "PostedBy") public String getPostedBy() { return postedBy; } public void setPostedBy(String postedBy) { this.postedBy = postedBy; } @DynamoDBIndexRangeKey(globalSecondaryIndexName = "PostedBy-Message-Index", attributeName = "Message") public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } // Additional properties go here. }

@DynamoDBTable 注釈は、このインデックスが Reply テーブルに関連付けられていることを示します。@DynamoDBIndexHashKey 注釈はインデックスのパーティションキー (PostedBy) を示し、@DynamoDBIndexRangeKey はインデックスのソートキー (Message) を示します。

ここで、DynamoDBMapper を使用してインデックスにクエリを実行し、特定のユーザーによって投稿されたメッセージのサブセットを取得できます。テーブル間やインデックス間でマッピングが競合せず、マッピングが既にマッパーで行われている場合は、インデックス名を指定する必要はありません。マッパーは、プライマリキーとソートキーに基づいて推論します。次のコードでは、グローバルセカンダリインデックスをクエリしています。グローバルセカンダリインデックスは、結果整合性のある読み込みをサポートしますが、強力な整合性のある読み込みはサポートしていないため、withConsistentRead(false) を指定する必要があります。

HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS("User A")); eav.put(":v2", new AttributeValue().withS("DynamoDB")); DynamoDBQueryExpression<PostedByMessage> queryExpression = new DynamoDBQueryExpression<PostedByMessage>() .withIndexName("PostedBy-Message-Index") .withConsistentRead(false) .withKeyConditionExpression("PostedBy = :v1 and begins_with(Message, :v2)") .withExpressionAttributeValues(eav); List<PostedByMessage> iList = mapper.query(PostedByMessage.class, queryExpression);

このクエリでは、PostedByMessage オブジェクトのコレクションが返されます。

queryPage

テーブルまたはセカンダリインデックスのクエリを実行し、一致した結果を 1 ページ返します。query メソッドと同様、パーティションキー値とソートキー属性に適用されるクエリフィルタを指定する必要があります。ただし queryPage では、データの最初の "ページ"、つまり 1 MB 以内に収まるデータ量のみが返されます。

scan

テーブル全体またはセカンダリインデックスをスキャンします。オプションで FilterExpression を指定して結果セットをフィルタリングできます。

フォーラムスレッドの返信を格納する Reply というテーブルがあるとします。各スレッドの件名については、0 以上の返信を受け取ることができます。Reply テーブルのプライマリキーは、Id および ReplyDateTime フィールドで構成されます。ここで、Id はプライマリキーのパーティションキー、ReplyDateTime はソートキーを表します。

Reply ( Id, ReplyDateTime, ... )

Reply テーブルに Java クラスをマッピングした場合は、DynamoDBMapper を使用してテーブルをスキャンできます。たとえば、以下の Java コードは、Reply テーブル全体をスキャンし、特定の年の返信のみを返します。

HashMap<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":v1", new AttributeValue().withS("2015")); DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withFilterExpression("begins_with(ReplyDateTime,:v1)") .withExpressionAttributeValues(eav); List<Reply> replies = mapper.scan(Reply.class, scanExpression);

デフォルトでは、scan メソッドによって、「遅延ロード」されたコレクションが返されます。最初に結果が 1 ページのみ返され、必要に応じて、さらに次ページを要求するサービス呼び出しが行われます。一致するすべての項目を取得するには、replies コレクションを反復処理します。

コレクションで size() メソッドを呼び出すと、正確なカウントを提供するためにすべての結果がロードされます。これにより、プロビジョニングされたスループットが大量に消費され、非常に大きなテーブルでは JVM 内のすべてのメモリが消費されることさえあります。

インデックスをスキャンするには、最初にインデックスをマッパークラスとしてモデリングする必要があります。今、Reply テーブルには、PostedBy-Message-Index という名前のグローバルセカンダリインデックスがあると仮定します。このインデックスのパーティションキーは PostedBy キーで、ソートキーは Message です。このインデックスのマッパークラスは、query セクションに示されています。また、@DynamoDBIndexHashKey@DynamoDBIndexRangeKey の注釈を使用して、インデックスパーティションキーとソートキーを指定します。

以下のサンプルコードでは PostedBy-Message-Index をスキャンします。スキャンフィルタを使用しないので、インデックス内のすべての項目が返されます。

DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withIndexName("PostedBy-Message-Index") .withConsistentRead(false); List<PostedByMessage> iList = mapper.scan(PostedByMessage.class, scanExpression); Iterator<PostedByMessage> indexItems = iList.iterator();

scanPage

テーブルまたはセカンダリインデックスがスキャンされ、一致する結果が 1 ページ返されます。scan メソッドと同様に、オプションで FilterExpression を指定して結果セットをフィルタリングできます。ただし、scanPage では、データの最初の "ページ"、つまり、1 MB 以内に収まるデータ量のみが返されます。

parallelScan

テーブル全体、またはセカンダリインデックスの並列スキャンが実行されます。テーブルの論理セグメントの数と、結果をフィルタするスキャン式を指定します。parallelScan では、スキャンタスクが複数のワーカーに分割され、論理セグメントごとに 1 つのワーカーが割り当てられます。ワーカーは、データを並列に処理し、結果を返します。

次の Java コード例では、Product テーブルに対して並列スキャンを実行します。

int numberOfThreads = 4; Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>(); eav.put(":n", new AttributeValue().withN("100")); DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() .withFilterExpression("Price <= :n") .withExpressionAttributeValues(eav); List<Product> scanResult = mapper.parallelScan(Product.class, scanExpression, numberOfThreads);

batchSave

AmazonDynamoDB.batchWriteItem メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルにオブジェクトを保存します。このメソッドでは、トランザクション保証はなされません。

次の Java コードでは、2 つの項目 (書籍) を ProductCatalog テーブルに保存します。

Book book1 = new Book(); book1.setId(901); book1.setProductCategory("Book"); book1.setTitle("Book 901 Title"); Book book2 = new Book(); book2.setId(902); book2.setProductCategory("Book"); book2.setTitle("Book 902 Title"); mapper.batchSave(Arrays.asList(book1, book2));

batchLoad

テーブルのプライマリキーを使用して、1 つ以上のテーブルから複数の項目を取り出します。

次の Java コードでは、2 つの異なるテーブルから 2 つの項目を取得します。

ArrayList<Object> itemsToGet = new ArrayList<Object>(); ForumItem forumItem = new ForumItem(); forumItem.setForumName("Amazon DynamoDB"); itemsToGet.add(forumItem); ThreadItem threadItem = new ThreadItem(); threadItem.setForumName("Amazon DynamoDB"); threadItem.setSubject("Amazon DynamoDB thread 1 message text"); itemsToGet.add(threadItem); Map<String, List<Object>> items = mapper.batchLoad(itemsToGet);

batchDelete

AmazonDynamoDB.batchWriteItem メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルからオブジェクトを削除します。このメソッドでは、トランザクション保証はなされません。

次の Java コードでは、2 つの項目 (書籍) を ProductCatalog テーブルから削除します。

Book book1 = mapper.load(Book.class, 901); Book book2 = mapper.load(Book.class, 902); mapper.batchDelete(Arrays.asList(book1, book2));

バッチ書き込み

AmazonDynamoDB.batchWriteItem メソッドに対する 1 つ以上の呼び出しを使用して、1 つ以上のテーブルに対してオブジェクトの保存および削除を行います。このメソッドではトランザクション保証はなされず、バージョニング(条件付き入力または削除)もサポートされません。

次の Java コードでは、新しい項目を Forum テーブルと Thread テーブルに書き込み、ProductCatalog テーブルから項目を削除します。

// Create a Forum item to save Forum forumItem = new Forum(); forumItem.setName("Test BatchWrite Forum"); // Create a Thread item to save Thread threadItem = new Thread(); threadItem.setForumName("AmazonDynamoDB"); threadItem.setSubject("My sample question"); // Load a ProductCatalog item to delete Book book3 = mapper.load(Book.class, 903); List<Object> objectsToWrite = Arrays.asList(forumItem, threadItem); List<Book> objectsToDelete = Arrays.asList(book3); mapper.batchWrite(objectsToWrite, objectsToDelete);

transactionWrite

AmazonDynamoDB.transactWriteItems メソッドに対する 1 回の呼び出しを使用して、1 つまたは複数のテーブルに対してオブジェクトの保存および削除を行います。

トランザクション固有の例外のリストについては、「TransactWriteItems エラー」を参照してください。

DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「DynamoDB トランザクションで複雑なワークフローを管理する」を参照してください。

注記

このメソッドでは、以下をサポートしていません。

次の Java コードでは、ForumThread の各テーブルに、トランザクションとして新しい項目を書き込みます。

Thread s3ForumThread = new Thread(); s3ForumThread.setForumName("S3 Forum"); s3ForumThread.setSubject("Sample Subject 1"); s3ForumThread.setMessage("Sample Question 1"); Forum s3Forum = new Forum(); s3Forum.setName("S3 Forum"); s3Forum.setCategory("Amazon Web Services"); s3Forum.setThreads(1); TransactionWriteRequest transactionWriteRequest = new TransactionWriteRequest(); transactionWriteRequest.addPut(s3Forum); transactionWriteRequest.addPut(s3ForumThread); mapper.transactionWrite(transactionWriteRequest);

transactionLoad

AmazonDynamoDB.transactGetItems メソッドへの 1 回の呼び出しを使用して、1 つまたは複数のテーブルからオブジェクトをロードします。

トランザクション固有の例外のリストについては、「TransactGetItems エラー」を参照してください。

DynamoDB トランザクション、および提供されるアトミック性、整合性、分離、耐久性 (ACID) の保証の詳細については、「DynamoDB トランザクションで複雑なワークフローを管理する」を参照してください。

次の Java コードは、 ForumThread の各テーブルから、トランザクションとして一方の項目をロードします。

Forum dynamodbForum = new Forum(); dynamodbForum.setName("DynamoDB Forum"); Thread dynamodbForumThread = new Thread(); dynamodbForumThread.setForumName("DynamoDB Forum"); TransactionLoadRequest transactionLoadRequest = new TransactionLoadRequest(); transactionLoadRequest.addLoad(dynamodbForum); transactionLoadRequest.addLoad(dynamodbForumThread); mapper.transactionLoad(transactionLoadRequest);

count

指定されたスキャン式の値を求め、一致する項目数を返します。項目データは返されません。

generateCreateTableRequest

DynamoDB テーブルに対応する POJO クラスを解析し、そのテーブルの CreateTableRequest を返します。

Amazon S3 内にあるオブジェクトへのリンクを作成します。バケット名とキー名を指定する必要があります。キー名によって、バケット内のオブジェクトを一意に識別します。

createS3Link を使用するには、マッパークラスでゲッターメソッドとセッターメソッドを定義する必要があります。次のサンプルコードでは、これを示しており、新しい属性と getter/setter メソッドを CatalogItem クラスに追加しています。

@DynamoDBTable(tableName="ProductCatalog") public class CatalogItem { ... public S3Link productImage; .... @DynamoDBAttribute(attributeName = "ProductImage") public S3Link getProductImage() { return productImage; } public void setProductImage(S3Link productImage) { this.productImage = productImage; } ... }

次の Java コードでは、Product テーブルに書き込まれる新しい項目を定義しています。この項目には、製品イメージへのリンクが含まれ、そのイメージデータは Amazon S3 にアップロードされています。

CatalogItem item = new CatalogItem(); item.setId(150); item.setTitle("Book 150 Title"); String myS3Bucket = "myS3bucket"; String myS3Key = "productImages/book_150_cover.jpg"; item.setProductImage(mapper.createS3Link(myS3Bucket, myS3Key)); item.getProductImage().uploadFrom(new File("/file/path/book_150_cover.jpg")); mapper.save(item);

S3Link クラスには、他にも、Amazon S3 のオブジェクトを操作するためのさまざまなメソッドが用意されています。詳細については、「Javadocs for S3Link」を参照してください。

getS3ClientCache

Amazon S3 にアクセスする際の基盤となる S3ClientCache を返します。S3ClientCache は、AmazonS3Client オブジェクトのスマートマップです。複数のクライアントがある場合、S3ClientCache によって、AWS リージョン別にクライアントを整理しやすくなり、新しい Amazon S3 クライアントをオンデマンドで作成できるようになります。