테이블 및 인덱스 쿼리: Java - Amazon DynamoDB

테이블 및 인덱스 쿼리: Java

Query 작업을 사용하면 Amazon DynamoDB에서 테이블이나 보조 인덱스를 쿼리할 수 있습니다. 파티션 키 값과 등식 조건을 입력해야 합니다. 테이블 또는 인덱스에 정렬 키가 있는 경우 정렬 키 값과 조건을 제공하여 결과를 구체화할 수 있습니다.

참고

또한 AWS SDK for Java에서는 객체 지속성 모델을 제공하므로 DynamoDB 테이블로 클라이언트 측 클래스를 매핑할 수 있습니다. 이러한 접근 방식을 활용하면 작성해야 할 코드가 줄어듭니다. 자세한 내용은 Java: DynamoDBMapper 섹션을 참조하세요.

다음은 AWS SDK for Java Document 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 설정 - 강력한 일관된 읽기(Strongly Consistent Read)를 요청합니다.

이 예제에서는 모든 하위 수준 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을 가져옵니다. 결과를 단계별로 진행하여 더 이상 페이지가 없을 때까지 한 번에 한 페이지씩 처리합니다.

다음 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, ...)

이 예제에서는 포럼 "DynamoDB"의 "DynamoDB Thread 1" 스레드에 대한 회신 검색의 변형 작업을 실행합니다.

  • 스레드에 대한 회신을 찾습니다.

  • 결과 페이지당 항목 수에 대한 제한을 지정하여 스레드에 대한 회신을 찾습니다. 결과 세트의 항목 수가 페이지 크기를 초과하는 경우 첫 페이지 결과만 가져옵니다. 이 코딩 패턴에서는 코드가 쿼리 결과의 모든 페이지를 처리합니다.

  • 지난 15일 간에 해당하는 회신을 찾습니다.

  • 특정 날짜 범위에 해당하는 회신을 찾습니다.

    앞서 다룬 두 쿼리 모두 정렬 키 조건을 지정하여 쿼리 결과를 좁히고 여러 선택적 쿼리 파라미터를 사용하는 방법을 보여 줍니다.

참고

아래 코드 예제는 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()); } } }