我试图使用二级全局索引查询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);
所有我想做的是得到所有项目的时间戳大于值不考虑键。
这不是Amazon DynamoDB上Global Secondary Indexes (GSI)的工作方式。要查询GSI, 必须为其散列键指定一个值,然后可以按范围键进行过滤/排序——就像处理主键一样。这正是异常试图告诉您的,也是您将在Query
API:
查询操作使用表的主键直接访问表中的项,或者使用索引键直接访问索引。必须提供一个特定的哈希键值
把GSI看作是另一个与主键行为几乎完全相同的键(主要区别在于它是异步更新的,并且您只能在GSI上执行最终一致的读取)。
请参阅Amazon DynamoDB Global Secondary Index文档页面,了解创建gsi时的指导方针和最佳实践:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html
实现您想要的一种可能的方法是将虚拟属性约束为有限的小可能值集,在该虚拟属性上创建一个具有散列键的GSI,并在时间戳上创建范围键。查询时,需要对虚拟散列键属性上的每个可能值发出一个Query API调用,然后在应用程序上合并结果。通过将dummy属性约束为单例(即,具有单个元素的Set,即常量值),您可以只发送一个Query API调用并直接获得结果数据集——但请记住,这将导致与热分区相关的问题,并且可能会出现性能问题!同样,请参考上面链接的文档来学习最佳实践和一些模式。
仅使用GSI可以查询DynamoDb;可以通过web界面查询/索引进行确认。
的编程方式如下:
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());
}
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSIJavaDocumentAPI.html GSIJavaDocumentAPI.QueryAnIndex
对于使用DynamoDBMapper进行操作,请参见:如何使用DynamoDBMapper查询具有仅hashKeys的GSI的DynamoDB
下面是如何在java中仅使用GSI进行查询
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);
虽然这不是正确的答案,但您是否可以通过扫描而不是查询来完成此任务?这要贵得多,但不失为一种解决办法。