テーブルおよびインデックスにクエリを実行 : Java - Amazon DynamoDB

テーブルおよびインデックスにクエリを実行 : Java

Query オペレーションを使用すると、Amazon DynamoDB でテーブルまたはセカンダリインデックスのクエリを実行できます。この関数ではパーティションキー値と等価条件を指定する必要があります。テーブルまたはインデックスにソートキーがある場合は、ソートキー値と条件を指定することで結果を絞り込むことができます。

注記

AWS SDK for Java には、オブジェクト永続性モデルも用意されています。このモデルにより、クライアント側のクラスを DynamoDB テーブルにマッピングすることができます。この方法により、記述する必要のあるコードの量を減らすことができます。詳細については、「」を参照してくださいJava: DynamoDBMapper

次に、AWS SDK for Java ドキュメント API を使用して項目を取り出すステップを示します。

  1. DynamoDB クラスのインスタンスを作成します。

  2. 操作対象のテーブルを表すために、Table クラスのインスタンスを作成します。

  3. query インスタンスの Table メソッドを呼び出します。任意のオプションクエリパラメータとともに、取得する項目のパーティションキー値を指定する必要があります。

応答には、クエリによって返されたすべての項目を示す ItemCollection オブジェクトが含まれています。

以下の Java コード例は、前述のタスクの例です。この例では、フォーラムスレッドへの返信を格納する Reply テーブルがあることを前提としています。詳細については、「」を参照してくださいDynamoDB でのコード例用のテーブルの作成とデータのロード

Reply ( Id, ReplyDateTime, ... )

各フォーラムスレッドには一意の ID があり、0 またはそれ以上の返信を受け取ることができます。つまり、Id テーブルの Reply 属性は、フォーラム名とフォーラムの件名の両方で構成されています。 Id (パーティションキー) と ReplyDateTime (ソートキー) が、テーブルの複合プライマリキーを構成しています。

次のクエリでは、特定のスレッド件名に対するすべての返信を取り出します。このクエリでは、テーブル名と Subject の両方の値が必要になります。

AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard() .withRegion(Regions.US_WEST_2).build(); DynamoDB dynamoDB = new DynamoDB(client); Table table = dynamoDB.getTable("Reply"); QuerySpec spec = new QuerySpec() .withKeyConditionExpression("Id = :v_id") .withValueMap(new ValueMap() .withString(":v_id", "Amazon DynamoDB#DynamoDB Thread 1")); ItemCollection<QueryOutcome> items = table.query(spec); Iterator<Item> iterator = items.iterator(); Item item = null; while (iterator.hasNext()) { item = iterator.next(); System.out.println(item.toJSONPretty()); }

オプションパラメータの指定

query メソッドでは、複数のオプションパラメータがサポートされています。たとえば、必要に応じて条件を指定して前述のクエリの結果を絞り込み、過去 2 週間の返信が返されるようにできます。この条件はソートキー条件と呼ばれます。指定したクエリ条件が DynamoDB によってプライマリキーのソートキーに対して評価されるためです。その他のオプションパラメータを指定して、クエリ結果の項目から特定の属性のリストだけを取り出すこともできます。

次の Java コード例では、過去 15 日間に投稿されたフォーラムスレッドの返信が取り出されます。この例では、次のものを使用してオプションパラメータを指定しています。

  • KeyConditionExpression - 特定のディスカッションフォーラムからの返信を取得し (パーティションキー)、その項目のセット内では、過去 15 日の間に投稿された返信を取得します (ソートキー)。

  • FilterExpression - 特定のユーザーからの返信だけを返します。フィルタは、クエリの処理の終了後、ユーザーに結果が返される前に適用されます。

  • ValueMap - KeyConditionExpression プレースホルダーの実際の値を定義します。

  • ConsistentRead - true に設定すると、強力な整合性のある読み込みをリクエストします。

この例では、すべての低レベル QuerySpec 入力パラメータにアクセスできる Query オブジェクトを使用します。

Table table = dynamoDB.getTable("Reply"); long twoWeeksAgoMilli = (new Date()).getTime() - (15L*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); QuerySpec spec = new QuerySpec() .withKeyConditionExpression("Id = :v_id and ReplyDateTime > :v_reply_dt_tm") .withFilterExpression("PostedBy = :v_posted_by") .withValueMap(new ValueMap() .withString(":v_id", "Amazon DynamoDB#DynamoDB Thread 1") .withString(":v_reply_dt_tm", twoWeeksAgoStr) .withString(":v_posted_by", "User B")) .withConsistentRead(true); ItemCollection<QueryOutcome> items = table.query(spec); Iterator<Item> iterator = items.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().toJSONPretty()); }

また、withMaxPageSize メソッドを使用して、ページあたりの項目数を制限することもできます。query メソッドを呼び出すと、結果の項目が含まれている ItemCollection が返されます。その後、結果を 1 ページずつ、最後のページまで処理していくことができます。

次の Java コード例では、前に示したクエリの仕様を変更します。今回、クエリの仕様は withMaxPageSize メソッドを使用します。Page クラスには、コードが各ページの項目を処理できるようにするイテレータがあります。

spec.withMaxPageSize(10); ItemCollection<QueryOutcome> items = table.query(spec); // Process each page of results int pageNum = 0; for (Page<Item, QueryOutcome> page : items.pages()) { System.out.println("\nPage: " + ++pageNum); // Process each item on the current page Iterator<Item> item = page.iterator(); while (item.hasNext()) { System.out.println(item.next().toJSONPretty()); } }

例 – Java を使用したクエリ

以下のテーブルには、フォーラムのコレクションに関する情報が格納されています。詳細については、「」を参照してくださいDynamoDB でのコード例用のテーブルの作成とデータのロード

注記

SDK for Java には、オブジェクト永続性モデルも用意されています。このモデルにより、クライアント側のクラスを DynamoDB テーブルにマッピングできます。この方法により、記述する必要のあるコードの量を減らすことができます。詳細については、「」を参照してくださいJava: DynamoDBMapper

Forum ( Name, ... ) Thread ( ForumName, Subject, Message, LastPostedBy, LastPostDateTime, ...) Reply ( Id, ReplyDateTime, Message, PostedBy, ...)

この Java コードの例では、「DynamoDB」フォーラムの「DynamoDB Thread 1」スレッドに対するさまざまな返信の検索を実行します。

  • スレッドに対する返信を検索します。

  • 結果のページあたりの項目数に対する制限を指定して、スレッドへの返信を探します。結果セットの項目数がページサイズを超えた場合は、結果の最初のページだけが得られます。このコーディングパターンによって、確実にクエリ結果の全ページがコードで処理されます。

  • 過去 15 日間の返信を検索します。

  • 特定の日付範囲の返信を検索します。

    前述の 2 つのクエリはどちらも、ソートキー条件を指定してクエリ結果を絞り込む方法、必要に応じてその他のクエリパラメータを使用する方法を示しています。

注記

このコード例は、DynamoDB でのコード例用のテーブルの作成とデータのロード セクションの説明に従って、アカウントの DynamoDB にデータが既にロードされていることを前提としています。

以下の例を実行するための詳しい手順については、「Java コードの例」を参照してください。

/** * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * This file is licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. A copy of * the License is located at * * http://aws.amazon.com/apache2.0/ * * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package com.amazonaws.codesamples.document; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; import com.amazonaws.services.dynamodbv2.document.DynamoDB; import com.amazonaws.services.dynamodbv2.document.Item; import com.amazonaws.services.dynamodbv2.document.ItemCollection; import com.amazonaws.services.dynamodbv2.document.Page; import com.amazonaws.services.dynamodbv2.document.QueryOutcome; import com.amazonaws.services.dynamodbv2.document.Table; import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec; import com.amazonaws.services.dynamodbv2.document.utils.ValueMap; public class DocumentAPIQuery { static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build(); static DynamoDB dynamoDB = new DynamoDB(client); static String tableName = "Reply"; public static void main(String[] args) throws Exception { String forumName = "Amazon DynamoDB"; String threadSubject = "DynamoDB Thread 1"; findRepliesForAThread(forumName, threadSubject); findRepliesForAThreadSpecifyOptionalLimit(forumName, threadSubject); findRepliesInLast15DaysWithConfig(forumName, threadSubject); findRepliesPostedWithinTimePeriod(forumName, threadSubject); findRepliesUsingAFilterExpression(forumName, threadSubject); } private static void findRepliesForAThread(String forumName, String threadSubject) { Table table = dynamoDB.getTable(tableName); String replyId = forumName + "#" + threadSubject; QuerySpec spec = new QuerySpec().withKeyConditionExpression("Id = :v_id") .withValueMap(new ValueMap().withString(":v_id", replyId)); ItemCollection<QueryOutcome> items = table.query(spec); System.out.println("\nfindRepliesForAThread results:"); Iterator<Item> iterator = items.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().toJSONPretty()); } } private static void findRepliesForAThreadSpecifyOptionalLimit(String forumName, String threadSubject) { Table table = dynamoDB.getTable(tableName); String replyId = forumName + "#" + threadSubject; QuerySpec spec = new QuerySpec().withKeyConditionExpression("Id = :v_id") .withValueMap(new ValueMap().withString(":v_id", replyId)).withMaxPageSize(1); ItemCollection<QueryOutcome> items = table.query(spec); System.out.println("\nfindRepliesForAThreadSpecifyOptionalLimit results:"); // Process each page of results int pageNum = 0; for (Page<Item, QueryOutcome> page : items.pages()) { System.out.println("\nPage: " + ++pageNum); // Process each item on the current page Iterator<Item> item = page.iterator(); while (item.hasNext()) { System.out.println(item.next().toJSONPretty()); } } } private static void findRepliesInLast15DaysWithConfig(String forumName, String threadSubject) { Table table = dynamoDB.getTable(tableName); long twoWeeksAgoMilli = (new Date()).getTime() - (15L * 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); String replyId = forumName + "#" + threadSubject; QuerySpec spec = new QuerySpec().withProjectionExpression("Message, ReplyDateTime, PostedBy") .withKeyConditionExpression("Id = :v_id and ReplyDateTime <= :v_reply_dt_tm") .withValueMap(new ValueMap().withString(":v_id", replyId).withString(":v_reply_dt_tm", twoWeeksAgoStr)); ItemCollection<QueryOutcome> items = table.query(spec); System.out.println("\nfindRepliesInLast15DaysWithConfig results:"); Iterator<Item> iterator = items.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().toJSONPretty()); } } private static void findRepliesPostedWithinTimePeriod(String forumName, String threadSubject) { Table table = dynamoDB.getTable(tableName); long startDateMilli = (new Date()).getTime() - (15L * 24L * 60L * 60L * 1000L); long endDateMilli = (new Date()).getTime() - (5L * 24L * 60L * 60L * 1000L); java.text.SimpleDateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); String startDate = df.format(startDateMilli); String endDate = df.format(endDateMilli); String replyId = forumName + "#" + threadSubject; QuerySpec spec = new QuerySpec().withProjectionExpression("Message, ReplyDateTime, PostedBy") .withKeyConditionExpression("Id = :v_id and ReplyDateTime between :v_start_dt and :v_end_dt") .withValueMap(new ValueMap().withString(":v_id", replyId).withString(":v_start_dt", startDate) .withString(":v_end_dt", endDate)); ItemCollection<QueryOutcome> items = table.query(spec); System.out.println("\nfindRepliesPostedWithinTimePeriod results:"); Iterator<Item> iterator = items.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().toJSONPretty()); } } private static void findRepliesUsingAFilterExpression(String forumName, String threadSubject) { Table table = dynamoDB.getTable(tableName); String replyId = forumName + "#" + threadSubject; QuerySpec spec = new QuerySpec().withProjectionExpression("Message, ReplyDateTime, PostedBy") .withKeyConditionExpression("Id = :v_id").withFilterExpression("PostedBy = :v_postedby") .withValueMap(new ValueMap().withString(":v_id", replyId).withString(":v_postedby", "User B")); ItemCollection<QueryOutcome> items = table.query(spec); System.out.println("\nfindRepliesUsingAFilterExpression results:"); Iterator<Item> iterator = items.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next().toJSONPretty()); } } }