按date查询DynamoDB

我来自关系数据库背景,并试图与亚马逊的DynamoDB合作

我有一个表的哈希键“DataID”和一个范围“CreatedAt”和一堆项目在里面。

我试图获取所有在特定date之后创build并按datesorting的项目。 这在关系数据库中是非常简单的。

在DynamoDB中,我能find的最接近的是一个查询,并使用大于filter的范围键。 唯一的问题是,执行一个查询,我需要一个散列键,击败目的。

那么我做错了什么? 我的表模式是错误的,不应该是唯一的散列键? 还是有另一种方式来查询?

已更新答案:

DynamoDB允许指定辅助索引来辅助这种查询。 二级索引可以是全局的,也就是说索引跨越散列键跨越整个表,或者本地意味着索引将存在于每个散列键分区内,因此在进行查询时也要指定散列键。

对于这个问题中的用例,你会想在“CreatedAt”字段上使用全局二级索引。

有关DynamoDB二级索引的更多信息, 请参阅二级索引文档

原始答案:

DynamoDB只允许在范围键上进行索引查找。 散列键是必需的,以便服务知道要查找哪个分区来查找数据。

你当然可以执行一个扫描操作来过滤date值,但是这将需要一个完整的表扫描,所以它不是理想的。

如果您需要跨多个主键对logging进行索引查找,则DynamoDB可能不是您理想的服务,或者您可能需要使用单独的表(在DynamoDB或关系存储中)来存储项目元数据,您可以执行索引查找。

鉴于您当前的表结构,这在DynamoDB中目前不可行。 巨大的挑战是要理解表(分区)的Hash键应该被视为创build单独的表。 在某些方面,这是非常强大的(把分区键看作为每个用户或客户创build一个新表格)。

查询只能在一个分区中完成。 这真是故事的结尾。 这意味着如果你想按date查询(你将要使用msec自epoch),那么你想在一个查询中检索的所有项目必须具有相同的散列(分区键)。

我应该限定这一点。 你绝对可以通过你正在寻找的标准进行scan ,这是没有问题的,但是这意味着你将查看表中的每一行,然后检查该行是否有与你的参数匹配的date。 这是非常昂贵的,特别是如果你是在日常事务中存储事件(即你有很多行)。

您可能会试图将所有数据都放在一个分区中来解决问题,而且您绝对可以,但是,由于每个分区仅接收总设置量的一小部分,所以吞吐量将会非常低。

最好的办法是确定更有用的分区来创build保存数据:

  • 你真的需要看所有的行,还是只有特定用户的行?

  • 首先按月份缩小列表,并做多个查询(每个月一个),可以吗? 还是按年份?

  • 如果您正在进行时间序列分析,有几个选项,将分区键更改为在PUT上进行计算以便query ,或者使用另一个aws产品(如kinesis),这些产品本身只能追加附加日志logging。

你的哈希键(首要的)必须是唯一的(除非你有一个像其他人所说的范围)。

在你的情况下,要查询你的表,你应该有一个二级索引。

 | ID | DataID | Created | Data | |------+--------+---------+------| | hash | xxxxx | 1234567 | blah | 

您的哈希键是ID您的二级索引被定义为:DataID-Created-index(这是DynamoDB将使用的名称)

然后,你可以这样查询:

 var params = { TableName: "Table", IndexName: "DataID-Created-index", KeyConditionExpression: "DataID = :v_ID AND Created > :v_created", ExpressionAttributeValues: {":v_ID": {S: "some_id"}, ":v_created": {N: "timestamp"} }, ProjectionExpression: "ID, DataID, Created, Data" }; ddb.query(params, function(err, data) { if (err) console.log(err); else { data.Items.sort(function(a, b) { return parseFloat(a.Created.N) - parseFloat(b.Created.N); }); // More code here } }); 

基本上你的查询看起来像:

 SELECT * FROM TABLE WHERE DataID = "some_id" AND Created > timestamp; 

二级索引将增加所需的读/写容量单位,因此您需要考虑这一点。 它仍然比扫描要好很多,读取和读取的时间都很昂贵(我相信这个数目只限于100个)。

这可能不是做这件事的最好方式,但对于习惯于RD的人(我也习惯于SQL),这是获得生产力的最快方法。 由于在架构方面没有任何限制,所以可以掀起一些有效的方法,一旦你有了最高效的带宽工作方式,你就可以改变这种状况。

您可以使Hash键沿着“产品类别”ID行,然后将范围键作为时间戳与末尾附加的唯一ID的组合。 这样你知道散列键,仍然可以查询大于的date。

我跟着解决这个问题的方法是创build一个全局二级索引如下。 不知道这是否是最好的方法,但希望如果这是有用的人。

 Hash Key | Range Key ------------------------------------ Date value of CreatedAt | CreatedAt 

限制HTTP API用户指定检索数据的天数,默认为24小时。

这样,我总是可以指定HashKey作为当前date,而RangeKey可以在检索时使用>和<操作符。 这样数据也分布在多个分片上。

你可以有多个相同的散列键; 但只有当你有一个范围键变化。 把它想像成文件格式; 只要格式不同,就可以在同一个文件夹中有两个同名的文件。 如果他们的格式是相同的,他们的名字必须是不同的。 相同的概念适用于DynamoDB的散列/范围键; 只要把hash作为名称和范围就可以了。

另外,我不记得在OP的时候他们是否有这些(我不相信他们),但他们现在提供本地二级指标。

我对这些的理解是,它现在应该允许您执行所需的查询,而无需执行完整的扫描。 缺点是这些索引必须在创build表时指定,而且(我相信)在创build项目时不能为空。 另外,它们需要额外的吞吐量(虽然通常不如扫描)和存储,所以它不是一个完美的解决scheme,但对于一些可行的替代scheme。

尽pipe如此,我仍然推荐Mike Brant的答案作为使用DynamoDB的首选方法。 并自己使用这种方法。 在我的情况下,我只有一个只有一个散列键作为我的ID的中央表,然后有一个散列和范围可以查询的次表,然后该项目代码指向中央表的“感兴趣的项目”,直接。

有关二级索引的其他数据可以在亚马逊的DynamoDB文档中find 。

无论如何,希望这将有助于任何其他人发生在这个线程。

您可以使用GSI在DynamoDB中执行此操作。 将“CreatedAt”字段设置为GSI,然后发出像(GT some_date)这样的查询。 将此date存储为此类查询的数字(自时代以来的msecs)。

有关详细信息,请访问:全局二级索引 – Amazon DynamoDB: http ://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using

这是一个非常强大的function。 请注意,查询仅限于(EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN)条件 – Amazon DynamoDB: http ://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html