Java 使用QuerySpec.withMaxPageSize()时在DynamoDB中分页

Java 使用QuerySpec.withMaxPageSize()时在DynamoDB中分页,java,pagination,amazon-dynamodb,Java,Pagination,Amazon Dynamodb,我想使用QuerySpec.withMaxPageSize(int-limit)实现分页。我是这样使用它的: QuerySpec querySpec = new QuerySpec() .withKeyConditionExpression("id = :v_id") .withValueMap(new ValueMap() .withString(":v_id", "1234")) .withScanIndexForwar

我想使用QuerySpec.withMaxPageSize(int-limit)实现分页。我是这样使用它的:

QuerySpec querySpec = new QuerySpec()
        .withKeyConditionExpression("id = :v_id")
        .withValueMap(new ValueMap()
            .withString(":v_id", "1234"))
        .withScanIndexForward(false)
        .withMaxPageSize(Integer.parseInt(5));
ItemCollection<QueryOutcome>items = table.query(querySpec);
int startPage = 0;
for (Page<Item, QueryOutcome> page : items.pages()) {
    System.out.println("Page: " + ++startPage);

    Iterator<Item> iterator = page.iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.next());
    }
}
QuerySpec querySpec = new QuerySpec()
    .withKeyConditionExpression("id = :v_id")
    .withFilterExpression("eventType = :v_eventType")
    .withValueMap(new ValueMap()
         .withString(":v_id", "1234")
         .withString(":v_eventType", "event"))
    .withScanIndexForward(false)
    .withMaxPageSize(Integer.parseInt(5));
那么结果是完全错误的:

Page: 1
{ Item: {id=1234, timestamp=1489480336243, eventType=starRating} }
{ Item: {id=1234, timestamp=1489476430129, eventType=starRating, }
{ Item: {id=1234, timestamp=1489460649642, eventType=starRating, }
Page: 2
{ Item: {id=1234, timestamp=1489137400014, eventType=starRating} }
Page: 3
{ Item: {id=1234, timestamp=1489137294383, eventType=starRating} }
Page: 4
{ Item: {id=1234, timestamp=1489137046331, eventType=starRating} }
Page: 5
{ Item: {id=1234, timestamp=1489137030983, eventType=starRating} }
{ Item: {id=1234, timestamp=1489137022138, eventType=starRating} }
Page: 6
{ Item: {id=1234, timestamp=1489136930427, eventType=starRating} }
Page: 7
{ Item: {id=1234, timestamp=1489136782467, eventType=starRating} }
{ Item: {id=1234, timestamp=1489136765162, eventType=starRating} }
{ Item: {id=1234, timestamp=1489136669765, eventType=starRating} }
Page: 8
{ Item: {id=1234, timestamp=1489136478857, eventType=starRating} }
{ Item: {id=1234, timestamp=1489136453453, eventType=starRating} }
{ Item: {id=1234, timestamp=1489136435202, eventType=starRating} }
{ Item: {id=1234, timestamp=1489136384098, eventType=starRating} }
Page: 9
{ Item: {id=1234, timestamp=1489136253163, eventType=starRating} }
每一页都有不同的项目。当我添加过滤器表达式时,似乎会出现这个问题。但我不知道为什么。有人知道这件事吗?

这里有一段摘录,解释了为什么每页的行数不同:

在响应中,DynamoDB返回 限制值的范围。例如,如果发出查询或扫描 限制值为6且没有筛选器表达式的请求, DynamoDB返回表中与 请求中指定的关键条件(或仅前六项) 在无过滤器的扫描情况下)。如果您还提供 FilterExpression值,DynamoDB将返回第一个 六个也符合筛选要求(结果数量 返回的值将小于或等于6)

所以基本上,当您在查询中使用FilterExpression和Limit时,DynamoDB从表中最多读取
Limit
记录,然后过滤掉与
FilterExpression
不匹配的记录


UPD:为了获得每页记录的确切数量,您必须使用更复杂的方法。在获得第一个查询结果后,如果返回的子集包含少于
Limit
项, 将记录保存到缓冲区并继续读取,直到项目总数达到>=限制。如果缓冲区中的记录数超过限制,请丢弃超过限制的记录。 这就是如何获得第一页的确切大小
Limit
项(在您的情况下为5项)

要获得第二个页面,可以运行一个新的查询,提供KeyConditionExpression,如
id=:v_id和#timestamp<:timestamp
,并使用上一页最后一条记录的timestamp值作为
:timestamp
。同样,您必须多次读取,直到缓冲区中的项目总数变成>=您首选的页面大小。使用相同的方法获取所有后续页面。

以下是一段摘录,解释了为什么每页的行数不同:

在响应中,DynamoDB返回 限制值的范围。例如,如果发出查询或扫描 限制值为6且没有筛选器表达式的请求, DynamoDB返回表中与 请求中指定的关键条件(或仅前六项) 在无过滤器的扫描情况下)。如果您还提供 FilterExpression值,DynamoDB将返回第一个 六个也符合筛选要求(结果数量 返回的值将小于或等于6)

所以基本上,当您在查询中使用FilterExpression和Limit时,DynamoDB从表中最多读取
Limit
记录,然后过滤掉与
FilterExpression
不匹配的记录


UPD:为了获得每页记录的确切数量,您必须使用更复杂的方法。在获得第一个查询结果后,如果返回的子集包含少于
Limit
项, 将记录保存到缓冲区并继续读取,直到项目总数达到>=限制。如果缓冲区中的记录数超过限制,请丢弃超过限制的记录。 这就是如何获得第一页的确切大小
Limit
项(在您的情况下为5项)

要获得第二个页面,可以运行一个新的查询,提供KeyConditionExpression,如
id=:v_id和#timestamp<:timestamp
,并使用上一页最后一条记录的timestamp值作为
:timestamp
。同样,您必须多次读取,直到缓冲区中的项目总数变成>=您首选的页面大小。使用相同的方法获取所有后续页面。

上述结果有一个错误:“eventType”的值应为“event”。我只是举一个例子说明我的问题。我没有看到任何一页有超过5个项目。是的,我知道答案。因为我使用FilterExpression。因此,结果将首先划分为多个页面,然后根据FilterExpression过滤每个页面中的结果。谢谢@efekctive!如果我使用上面的第二个
querySpec
,您知道如何实现分页吗?@xtx给出的解释似乎是合理的。如果我能想到任何其他的事情,我会发布上面的结果有一个错误:“eventType”的值应该是“event”。我只是举一个例子说明我的问题。我没有看到任何一页有超过5个项目。是的,我知道答案。因为我使用FilterExpression。因此,结果将首先划分为多个页面,然后根据FilterExpression过滤每个页面中的结果。谢谢@efekctive!如果我使用上面的第二个
querySpec
,您知道如何实现分页吗?@xtx给出的解释似乎是合理的。如果我能想到别的,我会发一封感谢信lot@xtx. 你完全解决了我的问题。另外,如果我想使用FilterExpression,我如何实现分页?Hi@xtx,我认为这个解决方案有点复杂,当我有大量项目时,这将非常缓慢。我想使用
LastEvaluatedKey
,但它似乎不支持
QuerySpec
ScanSpec
。QuerySpec和ScanSpec都支持ExclusiveStartKey,这是您从上一个结果传递LastEvaluatedKey值的地方。无论您是否使用
和ExclusiveStartKey
,或者使用附加时间戳条件的KeyConditionExpression来开始检索下一页的数据,为了获得每页相同的行数,您需要对每一页发出多个请求