Java 具有独占启动键的 DynamoDB 全局二级索引
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21730183/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DynamoDB Global Secondary Index with Exclusive Start Key
提问by rpmartz
Is it possible to specify an exclusive start key when querying a DynamoDB table via global secondary index?
通过全局二级索引查询DynamoDB表时是否可以指定独占启动键?
I'm using the aws-java-sdk version 1.6.10 and executing queries with a QueryExpression
and a DynamoDBMapper
. Here's the gist of what I'm trying to do:
我正在使用 aws-java-sdk 版本 1.6.10 并使用 aQueryExpression
和 a执行查询DynamoDBMapper
。这是我要做的事情的要点:
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);
This results in a 400 error saying that the specified start key is invalid. The TIMESTAMP is the range key for the table index and for the global secondary index, and the attribute value pair is valid (i.e. there is an item in the table with the values passed as the hash and range key for the index, and the attribute passed as the index is the hash key of the global secondary index).
这会导致 400 错误,指出指定的启动键无效。TIMESTAMP 是表索引和全局二级索引的范围键,属性值对是有效的(即表中有一个项目,其值作为索引的哈希和范围键传递,属性传递的索引是全局二级索引的哈希键)。
Is there something I missed or is this not possible?
有什么我错过的或者这是不可能的吗?
采纳答案by rpmartz
Per an Amazonian, this is not possible: https://forums.aws.amazon.com/thread.jspa?threadID=146102&tstart=0
对于亚马逊人来说,这是不可能的:https: //forums.aws.amazon.com/thread.jspa?threadID=146102&tstart=0
A workaround that worked for my use case, though, was to just specify a RangeKeyCondition
greater than the last retrieved object's timestamp. Here's the idea:
不过,对我的用例有效的解决方法是指定一个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;
Note that the marshallIntoObject
method is deprecated in favor of a protected method in the DynamoDBMapper
class, but it's easy enough to write a marshaller were a future upgrade to break the mapping.
请注意,该marshallIntoObject
方法已被弃用,以支持类中的受保护方法DynamoDBMapper
,但编写编组器很容易,如果将来升级以破坏映射。
Not as elegant as using the mapper but it accomplishes the same thing.
不像使用映射器那么优雅,但它完成了同样的事情。
回答by Naween Niroshan
Had the same issue and just got sorted. :) Too late to answer the question but hope someone will find helpful.
有同样的问题,刚刚得到排序。:) 回答这个问题为时已晚,但希望有人会觉得有帮助。
When you query or scan table with secondary indexes and pagination, you should include primary keys of the tableand the index(as key), with last evaluated values (as attribute value) when you setting ExclusiveStartKey.
当您使用二级索引和分页查询或扫描表时,您应该在设置ExclusiveStartKey时包括表的主键和索引(作为键),以及最后评估的值(作为属性值)。
Just Sysout the LastEvaluatedKeyfrom the query or scan result to see the format.
只需从查询或扫描结果中Sysout 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"));
回答by Bill Shubert
OK I'm super late to the party but I have figured out what is going on. This isn't a bug, it's working as it should, but I've never seen it in the documentation.
好吧,我参加聚会超级迟到了,但我已经弄清楚发生了什么。这不是错误,它可以正常工作,但我从未在文档中看到过它。
It turns out that in global secondary indexes, the primary indexes are used as "tiebreakers." That is, if two objects have the same GSI hash+sort keys, then the primary indexes are used to order them in the GSI. That means that when you query a GSI with an exclusive start key, you need both the GSI indexes andthe primary indexes in order to start at the exact right place.
事实证明,在全局二级索引中,一级索引被用作“决胜局”。也就是说,如果两个对象具有相同的 GSI 哈希+排序键,则使用主索引在 GSI 中对它们进行排序。这意味着当您使用独占启动键查询 GSI 时,您需要 GSI 索引和主索引才能从正确的位置开始。
Maybe this will help out somebody. I know it stumped me for a while!
也许这会帮助某人。我知道它难倒了我一段时间!