我有一个 DynamoDB 表,其中包含 PK id 和属性状态(布尔值)和类型(具有两个值的字符串)。我需要对状态和类型的结果过滤实现分页。我当前的方法使用 FilterExpression 进行扫描,并将 Limit 设置为 2 *desiredResultSize。我累积过滤结果直到达到desiredResultSize,然后根据最后过滤的项目生成一个nextToken供客户端在下一个请求中使用。 但是,我面临一些潜在的问题:
public PaginatedResult<List<ItemRecord>> getFilteredItems(String nextToken, int resultSize) {
Map<String, AttributeValue> exclusiveStartKey = decodeNextToken(nextToken);
Expression filterExpression = Expression.builder()
.expression("status = :status AND type IN (:type1, :type2)")
.expressionValues(Collections.unmodifiableMap(new HashMap<String, AttributeValue>() {{
put(":status", AttributeValue.fromBool(true));
put(":type1", AttributeValue.fromString("typeValue1"));
put(":type2", AttributeValue.fromString("typeValue2"));
}}))
.build();
ScanEnhancedRequest.Builder scanEnhancedRequestBuilder = ScanEnhancedRequest.builder()
.filterExpression(filterExpression)
.limit(resultSize);
// Accumulating results until desired resultSize is reached
// Create nextToken based on the last item in filteredItemsList
// Return the lastEvaluatedKey of the last found qualified item as nextToken
List<ItemRecord> filteredItemsList = new ArrayList<>();
Map<String, AttributeValue> currentExclusiveStartKey = exclusiveStartKey;
boolean findAllQualifiedItems = false;
while (!findAllQualifiedItems && filteredItemsList.size() < resultSize) {
try {
ScanEnhancedRequest scanEnhancedRequest = scanEnhancedRequestBuilder
.exclusiveStartKey(currentExclusiveStartKey).build();
Page<ItemRecord> itemRecordsList = table.scan(scanEnhancedRequest)
.stream().findFirst().orElse(null);
if (itemRecordsList.items().isEmpty()) {
break;
}
for (ItemRecord itemRecord : itemRecordsList.items()) {
if (filteredItemsList.size() < resultSize) {
filteredItemsList.add(itemRecord);
}
}
currentExclusiveStartKey = itemRecordsList.lastEvaluatedKey();
if (currentExclusiveStartKey == null) {
// We have found all qualified items in the table
findAllQualifiedItems = true;
}
} catch (Exception e) {
// handle it
}
}
if (filteredItemsList.isEmpty()) {
if (nextToken == null) {
throw new NotFoundException("Qualified items not found");
}
return new PaginatedResult<>(filteredItemsList, Optional.ofNullable(null), resultSize);
}
Map<String, AttributeValue> lastEvaluatedKey;
if (findAllQualifiedItems) {
lastEvaluatedKey = null;
} else {
lastEvaluatedKey = ConversionHelper.itemToAttributeValueMap(
filteredItemsList.get(filteredItemsList.size() - 1));
}
String newNextToken = ConversionHelper.encodeNextToken(lastEvaluatedKey);
return new PaginatedResult<>(filteredItemsList, Optional.ofNullable(newNextToken), resultSize);
}
感谢您的任何建议!
您的应用程序应确保您获得足够的项目来返回给用户,您返回的最后一个项目将是 LastEvaluatedKey。
使用扫描时,您永远不会知道是否有更多物品可供提取。
我建议更改您的数据模型以使用索引和查询而不是扫描,它更具可预测性,更不用说更高的性能和成本效益。