Java 仅使用二级全局索引查询 Dynamo 表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23621104/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 00:20:47  来源:igfitidea点击:

Query Dynamo table with only the secondary global index

javaamazon-web-servicesamazon-dynamodb

提问by webber

Im trying to query a Dynamodb table using a secondary global index and I'm getting java.lang.IllegalArgumentException: Illegal query expression: No hash key condition is found in the query. All I'm trying to do is to get all items that have a timestamp greater than a value without considering the key. The timestamp is not part of a key or range key, so i created a global index for it.

我试图使用二级全局索引查询 Dynamodb 表,但我得到 java.lang.IllegalArgumentException: Illegal query expression: No hash key condition is found in the query. 我要做的就是在不考虑键的情况下获取时间戳大于值的所有项目。时间戳不是键或范围键的一部分,所以我为它创建了一个全局索引。

Does anyone have a clue what i might be missing?

有谁知道我可能会错过什么?

Table Definition:

表定义:

{
   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
      }
   ]
}

Code

代码

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);

采纳答案by Bruno Reis

All I'm trying to do is to get all items that have a timestamp greater than a value without considering the key.

我要做的就是获取时间戳大于 value 的所有项目,而不考虑 key

This is not how Global Secondary Indexes(GSI) on Amazon DynamoDB work. To query a GSI you mustspecify a value for its hash key and then you may filter/sort by the range key -- just like you'd do with the primary key. This is exactly what the exception is trying to tell you, and also what you will find on the documentation page for the QueryAPI:

这不是Amazon DynamoDB 上的全局二级索引(GSI) 的工作方式。要查询 GSI,您必须为其散列键指定一个值,然后您可以按范围键进行过滤/排序——就像使用主键一样。这正是异常试图告诉您的内容,以及您将QueryAPI文档页面上找到的内容

A Query operation directly accesses items from a table using the table primary key, or from an index using the index key. You must provide a specific hash key value.

查询操作使用表主键直接访问表中的项目,或使用索引键从索引中访问项目。您必须提供特定的哈希键值。

Think of a GSI as just another keythat behaves almost exactly like the primary key (the main differences being that it is updated asynchronously, and you can only perform eventually consistent reads on GSIs).

将 GSI 视为另一个与主键几乎完全相同的键(主要区别在于它是异步更新的,并且您只能对 GSI 执行最终一致的读取)。

Please refer to the Amazon DynamoDB Global Secondary Index documentation page for guidelines and best practices when creating GSIs: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html

有关创建 GSI 的指南和最佳实践,请参阅 Amazon DynamoDB 全球二级索引文档页面:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html

One possible way to achieve what you want would be to have a dummyattribute constrained to a finite, small set of possible values, create a GSI with hash key on that dummy attribute and range key on your timestamp. When querying, you would need to issue one Query API call for each possible value on your dummy hash key attribute, and then consolidate the results on your application. By constraining the dummy attribute to a singleton (i.e., a Set with a single element, i.e., a constant value), you can send only one Query API call and you get your result dataset directly -- but keep in mind that this will cause you problems related to hot partitions and you might have performance issues! Again, refer to the document linked above to learn the best practices and some patterns.

实现您想要的一种可能的方法是将虚拟属性限制为有限的一小组可能值,在该虚拟属性上创建一个带有哈希键的 GSI,并在时间戳上创建范围键。查询时,您需要为虚拟哈希键属性上的每个可能值发出一个 Query API 调用,然后将结果合并到您的应用程序中。通过将 dummy 属性限制为单例(即具有单个元素的 Set,即常量值),您可以只发送一个 Query API 调用并直接获得结果数据集——但请记住,这会导致您的问题与热分区有关,您可能会遇到性能问题!同样,请参阅上面链接的文档以了解最佳实践和一些模式。

回答by James Parker

While this is not the correct answer per say, could you possible accomplish this with a scan vs. a query? It's much more expensive, but could be a solution.

虽然这不是正确的答案,但您是否可以通过扫描与查询来完成此操作?它要贵得多,但可能是一个解决方案。

回答by Neil

It is possible to query DynamoDb with only the GSI; could be confirmed by going to the web interaface Query/Index.

可以仅使用 GSI 查询 DynamoDb;可以通过访问 Web 界面查询/索引来确认。

Programatically the way it is done is as following:

以编程方式完成的方式如下:

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

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSIJavaDocumentAPI.html#GSIJavaDocumentAPI.QueryAnIndex

For doing it with DynamoDBMapper see: How to query a Dynamo DB having a GSI with only hashKeys using DynamoDBMapper

要使用 DynamoDBMapper 执行此操作,请参阅:如何使用 DynamoDBMapper查询仅具有哈希键的 GSI 的 Dynamo DB