当前位置: 首页 > 知识库问答 >
问题:

不使用分区键查询DynamoDB表的全局二级索引

蔡鸿骞
2023-03-14

我有一个DynamoDB表,分区键为userID,没有排序键。该表在每个项目中还具有时间戳属性。我想检索在指定范围内具有时间戳的所有项目(无论用户ID如何,即跨所有分区)。在阅读文档并搜索堆栈溢出(此处)后,我发现需要为我的表创建一个GSI。因此,我使用以下键创建了一个GSI:

  • 分区键:userID
  • 排序键:时间戳

我正在使用Java SDK使用以下代码查询索引:

String lastWeekDateString = getLastWeekDateString();
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("user table");
Index index = table.getIndex("userID-timestamp-index");

QuerySpec querySpec = new QuerySpec()
    .withKeyConditionExpression("timestamp > :v_timestampLowerBound")
    .withValueMap(new ValueMap()
            .withString(":v_timestampLowerBound", lastWeekDateString));

    ItemCollection<QueryOutcome> items = index.query(querySpec);
    Iterator<Item> iter = items.iterator();

while (iter.hasNext()) {
    Item item = iter.next();
    // extract item attributes here
}

执行此代码时出现以下错误:

Query condition missed key schema element: userID

据我所知,我应该能够仅使用排序键查询GSI,而不会在分区键上给出任何条件。请帮助我了解我的实现出了什么问题。谢谢。

编辑:在阅读了这里的线程之后,我们发现我们无法查询排序键上只有一个范围的GSI。那么,通过对属性进行范围查询来查询整个表的替代方法(如果有的话)是什么呢?我在该线程中发现的一个建议是使用year作为分区键。如果所需范围跨越多年,则需要进行多次查询。此外,这并没有将数据均匀地分布在所有分区上,因为只有与当前年份对应的分区将用于一整年的插入。请提出任何替代方案。

共有2个答案

龙德义
2023-03-14

对于DDB的任何定制查询需求,最好的解决方案是为GSI设计正确的主键方案。在设计DDB的主键时,主要原则是哈希键应设计用于对整个项目进行分区,排序键应设计用于对分区内的项目进行排序。

话虽如此,我建议您使用时间戳的年份作为哈希键,使用月份日期作为排序键。在这种情况下,最多只需进行2次查询。你是对的,你应该尽量避免过滤或扫描。

例如,您可以这样进行查询,如果开始日期的年份和结束日期的年份相同,您只需要一个查询:

.withKeyConditionExpression("#year = :year and #month-date > :start-month-date and #month-date < :end-month-date")

除此之外:

.withKeyConditionExpression("#year = :start-year and #month-date > :start-month-date")

.withKeyConditionExpression("#year = :end-year and #month-date < :end-month-date")

最后,您应该联合来自两个查询的结果集。这最多只消耗2个读取容量单位。

为了更好地比较排序键,您可能需要使用UNIX时间戳。

谢啦

蓝昊然
2023-03-14

使用dynamodb查询操作时,必须至少指定分区键。这就是为什么会出现需要用户ID的错误。(在AWS查询文档中)

条件必须对单个分区键值执行相等性测试。

获取没有分区键的项目的唯一方法是执行扫描操作(但这不会按排序键排序!)

如果您想对所有项目进行排序,您必须创建一个分区键的GSI,该分区键对您需要的所有项目都是相同的(例如,在所有项目上创建一个新属性,例如“type”:“Item”)。然后您可以查询GSI并指定#type=: Item

QuerySpec querySpec = new QuerySpec()
    .withKeyConditionExpression(":type = #item AND timestamp > :v_timestampLowerBound")
    .withKeyMap(new KeyMap()
            .withString("#type", "type"))
    .withValueMap(new ValueMap()
            .withString(":v_timestampLowerBound", lastWeekDateString)
            .withString(":item", "item"));

 类似资料:
  • 我有以下带有三个全局二级索引(GSI)的DyamoDB表 Id(主键)、user_id(GSI)、event_type(GSI)、product_id(GSI)、rate、create_date 我有以下三种查询模式: null null

  • 我正在DynamoDB中创建一个表和GSI,使用以下参数,如文档所示: 是表的主键,我使用作为GSI的主键。(为了简洁起见,我删除了一些不必要的配置参数) 我正在使用以下命令查询此表: 但我一直在犯错误: "一个或多个参数值无效:条件参数类型与模式类型不匹配" 在文档中,它指定主可以是或,并且您可以在字段中设置。我正在以的形式发送,不确定这里缺少了什么。 问题是在我创建表的方式上,还是在我查询表的

  • 我是AWS DynamoDB和nosql的新手,我对表创建有问题。 我试图创建一个名为的表,具有以下属性: 用户ID(HASH) OSType(范围) MSISDN IMSI 设备ID 我不仅需要通过查询表,还需要通过以下字段查询表: MSISDN 我的逻辑如下: 通过字段查询表 在阅读了有关LSI/GSI的手册后,我很难理解如何创建表和定义这些索引。 这是我尝试使用PHP AWS SDK创建表的

  • 本文(https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-indexes-gsi-sharding.html)讨论一种通过引入一个随机整数作为分区键,在多个分区之间对全局二级索引值进行分片的技术。 这对我来说是有意义的,但本文没有清楚地解释如何查询该索引。假设我使用一个1-10的随机整数作为分区键,一个数字作为排序

  • 我仍然对本地二级索引的使用感到困惑。当需要LSI与GSI时,请给我具体的用例。 例如,“GenreAlbumTitle”索引应该是GSI还是LSI?https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.Prim

  • DynamoDB表已经创建并在生产中运行。根据当前用例,计划添加新的辅助全局索引。这可以通过AWS实现SDK,是否可以使用CloudForm脚本更新DynamoDB表。 任何帮助都将不胜感激。