查询表和索引:Java
Query
支持在 Amazon DynamoDB 中查询表或二级索引。您必须提供分区键值和相等条件。如果表或索引具有排序键,则可通过提供排序键值和条件来优化结果。
Amazon SDK for Java 还提供一个对象持久化模型,可用来将客户端类映射到 DynamoDB 表。该方法可以减少您必须编写的代码数量。有关更多信息,请参阅 Java:DynamoDBMapper。
下面是使用 Amazon SDK for Java 文档 API 检索项目的步骤。
-
创建
DynamoDB
类的实例。 -
创建
Table
类的实例来代表要处理的表。 -
调用
query
实例的Table
方法。您必须指定要检索的项目的分区键值,以及任何可选的查询参数。
响应包括可以提供由查询返回的所有项目的 ItemCollection
对象。
以下 Java 代码示例演示了上述任务。该示例假定您有用于存储论坛话题回复的 Reply
表。有关更多信息,请参阅 为 DynamoDB 中的代码示例创建表和加载数据。
Reply ( Id, ReplyDateTime, ... )
每个论坛话题都有一个唯一 ID,并且可以有 0 个或更多个回复。因此,Reply
表的 Id
属性由论坛名称和论坛主题组成。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
方法支持多个可选参数。举例来说,您可以通过指定条件来缩小之前查询中的结果范围以返回过去两周内的回复。这一条件称为排序键条件,因为 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
。然后,您可以逐步处理结果,每次处理一页,直至完成所有页面。
以下 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 天内的回复。
-
查找特定日期范围内的回复。
之前的两个查询都演示了如何指定排序键条件来缩小查询结果范围以及如何使用其他可选查询参数。
此代码示例假定您已按照 为 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()); } } }