我来自关系数据库背景并尝试使用亚马逊的 DynamoDB
我有一个带有哈希键“DataID”和一个范围“CreatedAt”的表以及其中的一堆项目。
我正在尝试获取在特定日期之后创建并按日期排序的所有项目,这在关系数据库中非常简单。
在 DynamoDB 中,我能找到的最接近的东西是查询并使用大于过滤器的范围键。唯一的问题是,要执行查询,我需要一个无法达到目的的哈希键。
那么我做错了什么?我的表模式是否错误,哈希键不应该是唯一的吗?还是有其他查询方式?
我来自关系数据库背景并尝试使用亚马逊的 DynamoDB
我有一个带有哈希键“DataID”和一个范围“CreatedAt”的表以及其中的一堆项目。
我正在尝试获取在特定日期之后创建并按日期排序的所有项目,这在关系数据库中非常简单。
在 DynamoDB 中,我能找到的最接近的东西是查询并使用大于过滤器的范围键。唯一的问题是,要执行查询,我需要一个无法达到目的的哈希键。
那么我做错了什么?我的表模式是否错误,哈希键不应该是唯一的吗?还是有其他查询方式?
鉴于您当前的表结构,这在 DynamoDB 中目前是不可能的。巨大的挑战是要理解表(分区)的哈希键应该被视为创建单独的表。在某些方面,这确实很强大(将分区键视为为每个用户或客户创建一个新表,等等......)。
查询只能在单个分区中完成。这真的是故事的结局。这意味着如果您想按日期查询(您将希望使用自纪元以来的毫秒),那么您要在单个查询中检索的所有项目都必须具有相同的哈希(分区键)。
我应该限定这个。您绝对可以scan
按照您正在寻找的标准,这没问题,但这意味着您将查看表中的每一行,然后检查该行是否具有与您的参数匹配的日期。这真的很昂贵,特别是如果您首先要按日期存储事件(即您有很多行)。
您可能很想将所有数据放在一个分区中来解决问题,而且您绝对可以,但是您的吞吐量会非常低,因为每个分区只接收总设置量的一小部分。
最好的办法是确定要创建的更有用的分区来保存数据:
您真的需要查看所有行,还是仅查看特定用户的行?
可以先按月缩小列表范围,然后进行多个查询(每个月一个)吗?还是按年份?
如果您正在执行时间序列分析,有几个选项,将分区键更改为计算上的内容PUT
以使其query
更容易,或者使用其他 aws 产品(如 kinesis),它适用于仅附加日志记录。
更新答案:
DynamoDB 允许指定二级索引以帮助进行此类查询。二级索引可以是全局的,即索引跨越散列键跨越整个表,也可以是局部的,即索引将存在于每个散列键分区中,因此在进行查询时也需要指定散列键。
对于此问题中的用例,您可能希望在“CreatedAt”字段上使用全局二级索引。
有关 DynamoDB 二级索引的更多信息,请参阅二级索引文档
原答案:
DynamoDB 不允许仅对范围键进行索引查找。需要哈希键,以便服务知道要查找哪个分区来查找数据。
您当然可以执行扫描操作以按日期值进行过滤,但这需要全表扫描,因此并不理想。
如果您需要跨多个主键按时间对记录执行索引查找,DynamoDB 可能不是您使用的理想服务,或者您可能需要使用单独的表(在 DynamoDB 中或关系存储中)来存储项目您可以对其执行索引查找的元数据。
我用来解决这个问题的方法是创建一个全局二级索引,如下所示。不确定这是否是最好的方法,但希望它对某人有用。
Hash Key | Range Key
------------------------------------
Date value of CreatedAt | CreatedAt
限制 HTTP API 用户指定检索数据的天数,默认为 24 小时。
这样,我总是可以将 HashKey 指定为当前日期,并且 RangeKey 可以在检索时使用 > 和 < 运算符。这样,数据也分布在多个分片中。
您的哈希键(主要排序)必须是唯一的(除非您有其他人所说的范围)。
在您的情况下,要查询您的表,您应该有一个二级索引。
| 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)的人来说,这是获得生产力的最快方法。由于在模式方面没有任何限制,因此您可以制作一些可行的东西,一旦您有足够的带宽以最有效的方式工作,您就可以改变它。
您可以按照“产品类别”ID 的方式制作哈希键,然后将范围键作为时间戳与末尾附加的唯一 ID 的组合。这样你就知道哈希键并且仍然可以查询大于的日期。
您可以拥有多个相同的哈希键;但前提是您有一个变化的范围键。把它想象成文件格式;您可以在同一个文件夹中拥有 2 个同名文件,只要它们的格式不同。如果它们的格式相同,则它们的名称必须不同。相同的概念适用于 DynamoDB 的哈希/范围键;只需将哈希视为名称,将范围视为格式。
另外,我不记得他们在 OP 时是否有这些(我不相信他们有),但他们现在提供本地二级索引。
我对这些的理解是,它现在应该允许您执行所需的查询而无需进行全面扫描。缺点是必须在创建表时指定这些索引,并且(我相信)在创建项目时不能为空。此外,它们需要额外的吞吐量(尽管通常不如扫描那么多)和存储,因此对于某些人来说,这不是一个完美的解决方案,而是一个可行的替代方案。
不过,我仍然推荐 Mike Brant 的回答作为使用 DynamoDB 的首选方法;并自己使用该方法。就我而言,我只有一个只有哈希键作为我的 ID 的中央表,然后是具有可以查询的哈希和范围的辅助表,然后项目将代码指向中央表的“感兴趣的项目”,直接.
感兴趣的人可以在此处的 Amazon DynamoDB 文档中找到有关二级索引的其他数据。
无论如何,希望这将有助于在此线程上发生的其他任何人。
工作查询 1.aws dynamodb scan --table-name tableName --region us-east-1 --filter-expression "begins_with(createdTm,:gen)" --expression-attribute-values "{ ":gen":{"S":"2021-04-15"}}'--select "COUNT "
2.aws dynamodb 扫描 --table-name tableName --region us-east-1 --filter-expression "createdTm BETWEEN :v1 AND :v2" --expression-attribute-values '{":v1":{"S ":"2021-04-13"}, ":v2":{"S":"2021-04-14"}}' --选择 "COUNT"
更新的答案 使用具有可预测吞吐量的 Dynamo DB 查询没有方便的方法来执行此操作。一个(次优)选项是使用带有人工 HashKey 和 CreatedAt 的 GSI。然后单独通过 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