如何使用AWS SDK for Java在Amazon DynamoDB中使用分页

scyqe7ek  于 2023-03-11  发布在  Java
关注(0)|答案(2)|浏览(116)

根据this documentation from AWS,可以在Amazon DynamoDB上进行分页查询,但它没有提供任何关于如何进行的示例,它只说使用迭代器方法,这是我在使用DynamoDBMapper.query()后在PaginatedQueryList上找到的。
有人能解释一下它是如何工作的,如何正确使用它,以及当你不想像扫描操作那样一次从dynamoDB中检索所有结果时,它是否真的值得使用吗?

nnt7mjpx

nnt7mjpx1#

要了解Amazon DynamoDB Java API,请参阅AWS Java Developer Guide。要使用分页结果(当响应对象太大而无法在单个响应中返回时),最佳做法是使用AWS SDK for Java V2
AWS SDK for Java 1.0中,响应包含您必须用于检索下一页结果的令牌。AWS SDK for Java 2.x中的新增功能是自动生成方法,可进行多个服务调用以自动获取下一页结果。
有关详细信息,请参见Java V2 DEV Guide中的文档主题:
Retrieving paginated results using the AWS SDK for Java 2.x
要查看使用DynamoDB Java V2和分页的代码示例,请参见:
https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java

bnl4lu3b

bnl4lu3b2#

使用DynamoDB没有完全原生的方式来使用页码分页。主要是因为DynamoDB的分布式特性-表存储在多个分区中(mb甚至在多个服务器中)。此外,在DynamoDB中,从查询中检索的每条记录都有直接成本,所以我敢打赌您不想运行类似于计数查询的东西。
但是如果你想要实现像无限滚动或者“显示更多效果”这样的东西,有一种方法可以做到。以下示例实际适用于AWS Java SDK v2 2. 20. 7。该示例显示了增强型客户端的用法。

型号:

@Data
@DynamoDbBean
@FieldNameConstants
public class Event {

  @Getter(onMethod_ = {@DynamoDbPartitionKey})
  private String id;
  private String name;
  private String description;
  @Getter(onMethod_ = {@DynamoDbSecondaryPartitionKey(indexNames = "GSI_CREATOR")})
  private String creatorId;
  @Getter(onMethod_ = {@DynamoDbAutoGeneratedTimestampAttribute})
  private Instant updatedAt;
}

分页示例以JUnit 5test的形式提供。

数据准备使用Easy Random lib

private static final TableSchema<Event> TABLE_SCHEMA = TableSchema.fromBean(Event.class);

  private static final String EVENT_TABLE_NAME = "events-table";
  private static final String CREATOR = UUID.randomUUID().toString();

  @BeforeEach
  public void initDataModel() {

    final var eventFileDynamoDbTable = enhancedClient.table(EVENT_TABLE_NAME, TABLE_SCHEMA);

    final var factory = new EasyRandom();

    event1 = factory.nextObject(Event.class);
    event1.setCreatorId(CREATOR);

    eventFileDynamoDbTable.putItem(event1);

    event2 = factory.nextObject(Event.class);
    event2.setCreatorId(CREATOR);

    eventFileDynamoDbTable.putItem(event2);
  }

  @AfterEach
  public void cleanUp() {
    final var table = enhancedClient.table(EVENT_TABLE_NAME, TABLE_SCHEMA);

    table.deleteItem(event1);
    table.deleteItem(event2);
  }

实际分页过程:

@Test
  void testSecondaryIndexSearch() {

    final var table = enhancedClient.table(EVENT_TABLE_NAME, TABLE_SCHEMA);

    // Use global secondary index
    final var secIndex = table.index("GSI_CREATOR");

    // Create a QueryConditional object that's used in the query operation.
    final var queryConditional = QueryConditional
        .keyEqualTo(Key.builder().partitionValue(event1.getCreatorId()).build());

    // Get items in the table with limit 1
    SdkIterable<Page<Event>> pages = secIndex.query(QueryEnhancedRequest.builder()
        .queryConditional(queryConditional)
        .limit(1)
        .build());
    
    Page<Event> next = pages.iterator().next();

    assertEquals(1, next.items().size());

    // retrieve last processed key. this cursor can be passed to a client. 
    // so, it will be able to retrieve data from where it left off in the next query
    final var cursor = next.lastEvaluatedKey();

    assertNotNull(cursor);

    // Get items in the table with limit 1 using cursor
    // in real world case cursor will be received from the client
    SdkIterable<Page<Event>> newPages = secIndex.query(QueryEnhancedRequest.builder()
        .queryConditional(queryConditional)
        .limit(2) // trying to fetch more then we have
        .exclusiveStartKey(cursor)
        .build());
    Page<Event> nextWithLast = newPages.iterator().next();

    assertEquals(1, nextWithLast.items().size());

    final var cursorLast = nextWithLast.lastEvaluatedKey();

    // there is no more data to check. so, it's the end of "pagination"
    assertNull(cursorLast);
  }

通知及结论:

  • LastEvaluatedKey* 基本上是记录的主键,其中查询操作暂时结束,并作为结果集的最后一个值返回。在本例中- idcreatorID
  • LastEvaluatedKey* 在两个条件下返回:
  • 查询结果达到limit上限(例如,DynamoDB查询操作将数据划分为1 MB大小)。
  • 如果已通过在查询中添加Limit参数指定了限制,则它将返回一个数据集,该数据集具有更多剩余记录以供下一页计算。

因此,可以以这种方式实现连续分页(无限滚动)。

相关问题