具有独占启动密钥的DynamoDB全局二级索引

时间:2014-02-12 14:05:38

标签: java amazon-web-services amazon-dynamodb

通过全局二级索引查询DynamoDB表时是否可以指定独占启动键?

我正在使用aws-java-sdk版本1.6.10并使用QueryExpressionDynamoDBMapper执行查询。这是我要做的事情的要点:

MappedItem key = new MappedItem();
item.setIndexedAttribute(attributeValue);

Map<String, AttributeValue> exclusiveStartKey = new HashMap<String, AttributeValue>();
exclusiveStartKey.put(MappedItem.INDEXED_ATTRIBUTE_NAME, new AttributeValue().withS(attributeValue));
exclusiveStartKey.put(MappedItem.TIMESTAMP, new AttributeValue().withN(startTimestamp.toString()));

DynamoDBQueryExpression<MappedItem> queryExpression = new DynamoDBQueryExpression<MappedItem>();
queryExpression.withIndexName(MappedItem.INDEX_NAME);
queryExpression.withConsistentRead(Boolean.FALSE);
queryExpression.withHashKeyValues(key);
queryExpression.setLimit(maxResults * 2);
queryExpression.setExclusiveStartKey(exclusiveStartKey);

这会导致400错误,指出指定的开始键无效。 TIMESTAMP是表索引和全局二级索引的范围键,属性值对是有效的(即表中有一个项目,其值作为索引的哈希和范围键传递,属性传递为索引是全局二级索引的哈希键)。

我有什么遗漏或这是不可能的吗?

3 个答案:

答案 0 :(得分:7)

有同样的问题,只是排序了。 :)回答这个问题太迟了,但希望有人能找到帮助。

当您使用二级索引和分页查询或扫描表时,您应该包括索引(作为键)的主键,以及最后评估的值(设置 ExclusiveStartKey 时的属性值。

从查询或扫描结果中查看 LastEvaluatedKey 以查看格式。

// let's just assume that we have a table to store details of products
Map<String, AttributeValue> exclusiveStartKey = new HashMap<String, AttributeValue>();
// primary key of the table
exclusiveStartKey.put("productId", new AttributeValue().withS("xxxx"));
exclusiveStartKey.put("produtSize", new AttributeValue().withS("XL"));
// primary key of the index
exclusiveStartKey.put("categoryId", new AttributeValue().withS("xx01"));
exclusiveStartKey.put("subCategoryId", new AttributeValue().withN("1"));

答案 1 :(得分:6)

根据亚马逊流域,这是不可能的:https://forums.aws.amazon.com/thread.jspa?threadID=146102&tstart=0

但是,对我的用例起作用的解决方法是仅指定比最后检索到的对象的时间戳更大的RangeKeyCondition。这是个主意:

Condition hashKeyCondition = new Condition();
hashKeyCondition.withComparisonOperator(ComparisonOperator.EQ).withAttributeValueList(new AttributeValue().withS(hashKeyAttributeValue));

Condition rangeKeyCondition = new Condition();
rangeKeyCondition.withComparisonOperator(ComparisonOperator.GT).withAttributeValueList(new AttributeValue().withN(timestamp.toString()));

Map<String, Condition> keyConditions = new HashMap<String, Condition>();
keyConditions.put(MappedItem.INDEXED_ATTRIBUTE_NAME, hashKeyCondition);
keyConditions.put(MappedItem.TIMESTAMP, rangeKeyCondition);


QueryRequest queryRequest = new QueryRequest();
queryRequest.withTableName(tableName);
queryRequest.withIndexName(MappedItem.INDEX_NAME);
queryRequest.withKeyConditions(keyConditions);

QueryResult result = amazonDynamoDBClient.query(queryRequest);

List<MappedItem> mappedItems = new ArrayList<MappedItem>();

for(Map<String, AttributeValue> item : result.getItems()) {
    MappedItem mappedItem = dynamoDBMapper.marshallIntoObject(MappedItem.class, item);
    mappedItems.add(mappedItem);
}

return mappedItems;

请注意,不推荐marshallIntoObject方法支持DynamoDBMapper类中的受保护方法,但编写marshaller非常容易,这是未来的升级以打破映射。

不像使用mapper那样优雅,但它完成了同样的事情。

答案 2 :(得分:0)

好的,我参加聚会太迟了,但是我知道发生了什么事。这不是一个错误,它应该可以正常工作,但是我从未在文档中看到它。

事实证明,在全局二级索引中,一级索引用作“抢劫者”。也就是说,如果两个对象具有相同的GSI哈希+排序键,则将使用主索引在GSI中对它们进行排序。这意味着,当您使用排他的开始键查询GSI时,您需要GSI索引主索引才能在正确的位置开始。

也许这会帮助别人。我知道它让我难过了一段时间!