【问题标题】:Query Dynamo table with only the secondary global index仅使用二级全局索引查询 Dynamodb 表
【发布时间】:2014-05-13 00:41:24
【问题描述】:

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

有人知道我可能缺少什么吗?

表定义:

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

【问题讨论】:

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


    【解决方案1】:

    我要做的只是获取时间戳大于值的所有项目不考虑密钥

    这不是 Amazon DynamoDB 上的全球二级索引 (GSI) 的工作方式。要查询 GSI,您必须为其哈希键指定一个值,然后您可以按范围键过滤/排序——就像您使用主键一样。这正是异常试图告诉您的内容,也是您将在documentation page for the Query API 上找到的内容:

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

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

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

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

    【讨论】:

    • 所以最终 NoSql 糟透了,考虑到使用 Sql 会多么容易
    • @vishal - 与其他所有技术一样,也需要权衡取舍。对于某些类型的应用程序,我完全同意你的看法,“NoSQL 很烂”。对于其他人,我肯定会说“SQL 很烂”。这只是拥有大量您所了解的技术并能够为工作选择合适的技术的问题。不幸的是,到目前为止,人类还没有能力创建一种单一的数据库技术,它具有所有“优点”而没有其他所有“缺点”......
    • NoSQL 通常不烂,但恕我直言 dynamodb 确实如此,很多。例如,在 mongodb 中,这将是微不足道的。
    【解决方案2】:

    可以仅使用 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());
    }
    

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

    如需使用 DynamoDBMapper,请参阅:How to query a Dynamo DB having a GSI with only hashKeys using DynamoDBMapper

    【讨论】:

      【解决方案3】:

      虽然这不是每个说法的正确答案,但您可以通过扫描与查询来完成此任务吗?它要贵得多,但可能是一种解决方案。

      【讨论】:

        【解决方案4】:

        这里是你如何在 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);
        

        【讨论】:

          猜你喜欢
          • 2023-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多