Answers:
更新的答案:
DynamoDB允许指定二级索引来帮助这种查询。二级索引可以是全局的(意味着该索引跨哈希键跨整个表),也可以是局部的(意味着该索引将存在于每个哈希键分区中),因此要求在进行查询时也指定哈希键。
对于此问题中的用例,您需要在“ CreatedAt”字段上使用全局二级索引。
有关DynamoDB二级索引的更多信息,请参见二级索引文档。
原始答案:
DynamoDB不允许仅在范围键上进行索引查找。哈希密钥是必需的,以便服务知道要查找哪个分区以查找数据。
您当然可以执行扫描操作以按日期值进行过滤,但是这将需要全表扫描,因此并不理想。
如果您需要跨多个主键按时间对记录进行索引查找,则DynamoDB可能不是您理想的服务,或者您可能需要利用单独的表(在DynamoDB或关系存储中)存储项目您可以执行索引查找的元数据。
考虑到您当前的表结构,DynamoDB当前无法做到这一点。巨大的挑战是要了解表(分区)的哈希键应视为创建单独的表。在某些方面,它确实非常强大(将分区键视为为每个用户或客户创建新表等)。
查询只能在单个分区中进行。那真的是故事的结局。这意味着,如果您要按日期查询(自纪元起便要使用毫秒),则要在单个查询中检索的所有项目都必须具有相同的哈希(分区键)。
我应该证明这个。您绝对可以scan
按照要查找的条件来进行操作,这没问题,但这意味着您将查看表中的每一行,然后检查该行是否具有与您的参数匹配的日期。这确实非常昂贵,尤其是如果您要首先按日期存储事件(即,您有很多行)。
您可能会想将所有数据放在一个分区中来解决该问题,您绝对可以,但是由于每个分区仅接收总设置量的一小部分,因此吞吐量会非常低。
最好的办法是确定要创建的更有用的分区来保存数据:
您是否真的需要查看所有行,还是仅查看特定用户的行?
首先按月份缩小列表范围,然后进行多个查询(每个月查询一次)是否可以?还是按年?
如果要进行时间序列分析,则有两个选项,可以将分区键更改为可简化计算PUT
的值query
,或者使用kinesis之类的其他AWS产品,使其适用于仅追加日志记录。
yyyy
并对其进行哈希处理,还创建一个created
日期,您可以将其用作范围键。然后,您每年可以获得10GB的数据(每天27 MB),这可能在更多情况下是可以的。这确实意味着,当日期查询超出年份边界时,您必须每年创建一个查询,但是至少它会起作用,并且比创建虚拟哈希键更安全。
您的哈希键(排序的主键)必须是唯一的(除非您具有其他人指出的范围)。
对于您的情况,要查询表,您应该有一个辅助索引。
| 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)的人来说,这是提高生产率的最快方法。由于对模式没有任何限制,因此您可以快速进行一些工作,一旦拥有了以最有效的方式工作的带宽,就可以进行更改。
您可以有多个相同的哈希键;但前提是您的范围键有所不同。可以将其视为文件格式;您可以在同一文件夹中使用相同名称的2个文件,只要它们的格式不同即可。如果它们的格式相同,则它们的名称必须不同。相同的概念适用于DynamoDB的哈希/范围键;只需将哈希视为名称,将范围视为格式。
另外,我不记得他们在OP时是否有这些文件(我不相信他们有),但是现在它们提供了本地二级索引。
我对这些的理解是,它现在应该允许您执行所需的查询,而不必进行全面扫描。缺点是必须在创建表时指定这些索引,并且(我相信)在创建项目时不能为空。此外,它们需要额外的吞吐量(尽管通常不如扫描那么多)和存储,因此对于某些人来说,这不是一个完美的解决方案,而是一个可行的选择。
我仍然建议Mike Brant的答案作为使用DynamoDB的首选方法。并自己使用该方法。在我的情况下,我只有一个仅具有哈希键作为ID的中央表,然后是具有可查询的哈希和范围的辅助表,然后该项目将代码直接指向中央表的“感兴趣的项目” 。
有关二级索引的其他数据,可以在此处的 Amazon DynamoDB文档中找到。
无论如何,希望这将对在此线程上发生的任何其他事件有所帮助。
更新的答案 没有使用可预测吞吐量的Dynamo DB查询执行此操作的便捷方法。一种(次优)选择是将GSI与人工HashKey和CreatedAt一起使用。然后仅通过HashKey进行查询,并提及ScanIndexForward以对结果进行排序。如果您可以提出一个自然的HashKey(例如商品的类别等),则此方法是一个赢家。另一方面,如果所有项目都使用相同的HashKey,则当数据集超过10GB(一个分区)时,它将主要影响吞吐量。
原始答案: 您现在可以使用GSI在DynamoDB中执行此操作。将“ CreatedAt”字段设置为GSI,并发出(GT some_date)之类的查询。对于此类查询,将日期存储为数字(自纪元以来的毫秒数)。
有关详细信息,请参见:全球二级索引-Amazon DynamoDB:http ://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using
这是一个非常强大的功能。请注意,查询仅限于(EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN)条件-Amazon DynamoDB:http ://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
CreatedAt
应该是GSI的范围键,则需要选择一个哈希键-然后返回到开始的位置,因为您将只能查询GT CreatedAt
的特定值散列键。
CreatedAt
大于某个特定点的所有记录。