按日期查询 DynamoDB

我来自一个关系数据库背景,正在尝试使用亚马逊的 DynamoDB

我有一个表,其中包含一个散列键“ DataID”和一个范围“ CreatedAt”以及一堆项目。

我试图得到所有的项目后创建一个特定的日期和排序的日期,这是非常简单的关系数据库。

在 DynamoDB 中,我能找到的最接近的东西是查询和使用范围键大于过滤器。唯一的问题是,要执行查询,我需要一个散列键,这违背了目的。

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

171414 次浏览

更新答案:

DynamoDB 允许指定辅助索引来辅助这类查询。次要索引可以是全局的,这意味着索引跨哈希键跨越整个表,也可以是本地的,这意味着索引将存在于每个哈希键分区中,因此在进行查询时也需要指定哈希键。

对于这个问题中的用例,您希望在“ CreatedAt”字段上使用全局辅助索引。

有关 DynamoDB 二级索引 请参阅辅助索引文档的详细信息,请参阅

原答案:

DynamoDB 不允许仅对范围键进行索引查找。哈希键是必需的,这样服务就知道要查找哪个分区来查找数据。

当然,您可以执行扫描操作来根据日期值进行过滤,但是这需要进行全表扫描,因此这并不理想。

如果您需要在多个主键之间按时间执行记录的索引查找,DynamoDB 可能不是您理想的使用服务,或者您可能需要使用一个单独的表(在 DynamoDB 或关系存储中)来存储可以执行索引查找的项元数据。

您可以将 Hash 键设置为类似于“ product type”id 的内容,然后将 range 键设置为时间戳和末尾附加的唯一 id 的组合。这样,您就知道了哈希键,并且仍然可以使用大于。

可以有多个相同的散列键; 但只有在范围键变化时才可以。可以把它想象成文件格式; 只要它们的格式不同,就可以在同一个文件夹中有两个名称相同的文件。如果它们的格式相同,则它们的名称必须不同。同样的概念也适用于 DynamoDB 的 hash/range 键; 只需将 hash 作为名称,将 range 作为格式。

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

我对这些的理解是,现在它应该允许您执行所需的查询,而不必进行全面扫描。缺点是这些索引必须在创建表时指定,而且(我相信)在创建项时不能为空。此外,它们还需要额外的吞吐量(尽管通常不像扫描那样多)和存储,因此这不是一个完美的解决方案,但对某些人来说是一个可行的替代方案。

不过,我仍然推荐 Mike Brant 的回答作为使用 DynamoDB 的首选方法; 并且我自己也使用这种方法。在我的例子中,我只有一个中心表,只有一个散列键作为我的 ID,然后有一个散列和可以查询的范围的次要表,然后项目指向中心表的“感兴趣的项目”,直接代码。

有关辅助索引的其他数据可以在 Amazon 的 DynamoDB 文档 给你中找到,供感兴趣的人参考。

无论如何,希望这能帮助任何人,发生在这个线程。

更新答案 使用具有可预测吞吐量的 DynamoDB 查询没有方便的方法来实现这一点。一个(次优)选项是使用带有人工 HashKey & CreatedAt 的 GSI。然后单独使用 HashKey 进行查询,并提及 ScanIndexForward 以排序结果。如果你能想出一个自然的 HashKey (比如项目的类别等等) ,那么这个方法就是赢家。另一方面,如果对所有项目保持相同的 HashKey,那么当数据集超过10GB (一个分区)时,它将主要影响吞吐量

原答案: 您现在可以通过使用 GSI 在 DynamoDB 中实现这一点。将“ CreatedAt”字段作为 GSI 并发出如下查询(GTsome _ date)。将这类查询的日期存储为数字(msec since epoch)。

详情请浏览此网页: 全球二级索引-亚马逊 DynamoDB: 使用 rel = “ nofollow noReferrer”http://docs.aws.Amazon.com/amazondynamodb/latest/developerguide/gsi.html#gsi.using

这是一个非常强大的特性。请注意,查询仅限于(EQ | LE | LT | GE | GT | BEGINS _ WITH | BETWEEN) 条件-亚马逊 DynamoDB: < a href = “ http://docs.aws.Amazon.com/amazondnamodb/best/APIReference/API _ Condition.html”rel = “ nofollow noReferrer”> http://docs.aws.Amazon.com/amazondynamodb/latest/apireference/api_condition.html

您的哈希键(主要的排序)必须是唯一的(除非您有一个范围,如其他人所述)。

在您的情况下,要查询表,您应该有一个辅助索引。

|  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 Key                 | Range Key
------------------------------------
Date value of CreatedAt  | CreatedAt

对 HTTPAPI 用户施加的限制是指定检索数据的天数,默认为24小时。

通过这种方式,我总是可以将 HashKey 指定为 Current date 的日期,而 RangeKey 在检索时可以使用 > 和 < 操作符。这样,数据也可以跨多个碎片分布。

考虑到当前的表结构,这在 DynamoDB 中当前是不可能的。最大的挑战是理解表(分区)的 Hash 键应该被视为创建单独的表。在某些方面,这确实很强大(可以将分区键想象为为每个用户或客户创建一个新表,等等)。.).

查询只能在单个分区中完成。故事到此结束。这意味着如果您想按日期进行查询(从纪元开始您将使用 msec) ,那么您想在一个查询中检索的所有项目必须具有相同的 Hash (分区键)。

我应该有资格。您完全可以按照您所寻找的标准使用 scan,这没有问题,但是这意味着您将查看表中的每一行,然后检查该行是否有与您的参数匹配的日期。这非常昂贵,特别是如果您从事的业务首先是按日期存储事件(即您有很多行)

您可能会试图将所有数据放在一个分区中来解决这个问题,而且您完全可以这样做,但是由于每个分区只能获得总设置量的一小部分,因此吞吐量会非常低。

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

  • 您真的需要查看所有行吗? 还是只需要查看特定用户的行?

  • 首先按月缩小列表范围,然后执行多个查询(每个月一个) ,这样可以吗?还是年份?

  • 如果你正在做时间序列分析,有两个选择,改变分区键的东西在 PUT上计算,使 query更容易,或者使用另一个像 kinesis 的劳动产品,借给自己附加-只记录。

工作查询 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 WEEN: v1 AND: v2”—— expression-tribute-values’{“ : v1”: {“ S”: “2021-04-13”} ,“ : v2”: {“ S”: “2021-04-14”}}’——选择“ COUNT”