我试图使用辅助全局索引查询Dynamodb表,并且我得到java.lang.IllegalArgumentException:非法查询表达式:在查询中找不到散列键条件。我试图做的就是在不考虑密钥的情况下获取时间戳大于值的所有项目。时间戳不是键或范围键的一部分,因此我为它创建了一个全局索引。
有没有人知道我可能会缺少什么?
表定义:
{
AttributeDefinitions:[
{
AttributeName:timestamp,
AttributeType:N
},
{
AttributeName:url,
AttributeType:S
}
],
TableName:SitePageIndexed,
KeySchema:[
{
AttributeName:url,
KeyType:HASH
}
],
TableStatus:ACTIVE,
CreationDateTime: Mon May 12 18:45:57 EDT 2014,
ProvisionedThroughput:{
NumberOfDecreasesToday:0,
ReadCapacityUnits:8,
WriteCapacityUnits:4
},
TableSizeBytes:0,
ItemCount:0,
GlobalSecondaryIndexes:[
{
IndexName:TimestampIndex,
KeySchema:[
{
AttributeName:timestamp,
KeyType:HASH
}
],
Projection:{
ProjectionType:ALL,
},
IndexStatus:ACTIVE,
ProvisionedThroughput:{
NumberOfDecreasesToday:0,
ReadCapacityUnits:8,
WriteCapacityUnits:4
},
IndexSizeBytes:0,
ItemCount:0
}
]
}
代码
Condition condition1 = new Condition().withComparisonOperator(ComparisonOperator.GE).withAttributeValueList(new AttributeValue().withN(Long.toString(start)));
DynamoDBQueryExpression<SitePageIndexed> exp = new DynamoDBQueryExpression<SitePageIndexed>().withRangeKeyCondition("timestamp", condition1);
exp.setScanIndexForward(true);
exp.setLimit(100);
exp.setIndexName("TimestampIndex");
PaginatedQueryList<SitePageIndexed> queryList = client.query(SitePageIndexed.class,exp);
答案 0 :(得分:5)
我尝试做的就是让所有时间戳大于 的项目而不考虑密钥 。
这不是Amazon DynamoDB上全局二级索引(GSI)的工作方式。要查询GSI,您必须为其哈希键指定一个值,然后您可以按范围键进行过滤/排序 - 就像您使用主键一样。这正是异常试图告诉您的内容,以及您在documentation page for the Query
API上会发现的内容:
Query操作使用表主键直接访问表中的项,或使用索引键从索引访问。 您必须提供特定的哈希键值。
将GSI视为只是另一个键,其行为几乎与主键完全相同(主要区别在于它是异步更新的,并且您只能在GSI上执行最终一致的读取)。 / p>
有关创建GSI时的指南和最佳做法,请参阅Amazon DynamoDB全球二级索引文档页面:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html
实现所需功能的一种可能方法是将虚拟属性约束为有限的一小组可能值,在该虚拟属性上创建一个带有散列键的GSI,并在其上创建范围键你的时间戳。查询时,您需要为虚拟哈希键属性上的每个可能值发出一个Query API调用,然后在应用程序上合并结果。通过将dummy属性约束为单例(即,具有单个元素的Set,即常量值),您只能发送一个Query API调用并直接获得结果数据集 - 但请记住,这会导致您遇到与热分区相关的问题,您可能会遇到性能问题!再次,请参阅上面链接的文档以了解最佳实践和一些模式。
答案 1 :(得分:1)
虽然这不是每个说法的正确答案,但是你可以通过扫描与查询完成此操作吗?它要贵得多,但可能是一个解决方案。
答案 2 :(得分:1)
可以仅使用GSI查询DynamoDb;可以通过访问网络交互式查询/索引来确认。
以编程方式完成它的方式如下:
DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient(
new ProfileCredentialsProvider()));
Table table = dynamoDB.getTable("WeatherData");
Index index = table.getIndex("PrecipIndex");
QuerySpec spec = new QuerySpec()
.withKeyConditionExpression("#d = :v_date and Precipitation = :v_precip")
.withNameMap(new NameMap()
.with("#d", "Date"))
.withValueMap(new ValueMap()
.withString(":v_date","2013-08-10")
.withNumber(":v_precip",0));
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator();
while (iter.hasNext()) {
System.out.println(iter.next().toJSONPretty());
}
使用DynamoDBMapper进行操作时,请参阅:How to query a Dynamo DB having a GSI with only hashKeys using DynamoDBMapper
答案 3 :(得分:0)
这是仅使用GSI在Java中进行查询的方式
Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
eav.put(":val1", new AttributeValue().withS("PROCESSED"));
DynamoDBQueryExpression<Package> queryExpression = new DynamoDBQueryExpression<Package>()
.withIndexName("<your globalsecondaryindex key name>")
.withKeyConditionExpression("your_gsi_column_name= :val1").
withExpressionAttributeValues(eav).withConsistentRead(false).withLimit(2);
QueryResultPage<T> scanPage = dbMapper.queryPage(T.class, queryExpression);