查询日期范围,当日期是唯一键时
Querying for a range of dates, when date is the only key
我想使用 DynamoDB 来存储历史股票收盘价。
我的商店将有一些存货,并随着需求的变化增加到更多存货。
我想我会有一个 table,其中唯一的键是 "DATE"
,格式为 YYYY-MM-DD
。
这意味着 table 中的每个项目都有一个 date
键和几个 { TICKER = CLOSING_VALUE }
形式的属性
给定日期的查询也将按所需股票代码的子集进行过滤,例如["INTC", "AAPL"]
.
我有点困惑,因为这个键应该同时用作分区键和排序键。
我应该如何查询以检索给定日期范围内的股票代码子集?
更新:
我正在创建table...
{
AttributeDefinitions: [
{
AttributeName: Date,
AttributeType: S
}
],
TableName: "Historic",
KeySchema: [
{
AttributeName: Date,
KeyType: HASH
}
]
}
以及查询:
{
table_name: "Historic",
projection_expression: "USD,CAD",
filter_expression: "#k between :val1 and :val2",
expression_attribute_names: { "#k" => "Date" },
expression_attribute_values: {
":val1" => "2019-12-01",
":val2" => "2020-01-10"
}
}
我得到一个错误:
Aws::DynamoDB::Errors::ValidationException: Either the KeyConditions or KeyConditionExpression parameter must be specified in the request.
您不能按 - 或 有效地 检索范围 - 分区键排序,您只能按排序键排序。要了解原因,您需要了解 DynamoDB 如何存储其数据。
"partition key" 在 CreateTable operation 中也被称为 "hash key" - 实际上它就像散列中的键一样工作 table:DynamoDB 在这个键,并使用结果数,决定它的大集群的哪个节点应该拥有这个分区。这种方法允许在集群中分布 table,但它不可能 有效地检索按其键排序的不同分区。 "Scan" 操作将 return 分区以看似随机的顺序排列(它们很可能按其键的哈希函数排序),并且不可能有效地仅扫描一系列分区键。这样做可能效率低下 - 通过扫描整个 table 和 过滤 只是您想要的分区。如果我理解正确的话,这就是你想要做的。但这只对小型数据库有意义 - 你会这样吗?
如您所见,密钥的另一个组成部分是 "sort key"。在一个分区内,在一个节点中,该分区中的不同项目按 "sort key" 顺序保持顺序排序。这允许 DynamoDB 有效地检索按此顺序排序的它们,或者有效地仅检索这些排序键的范围 - Query
请求可以完成这两项工作。
因此,要实现您想要的效果,您需要将日期作为 排序键,而不是分区键。如何进行其余数据建模取决于您的典型查询:
如果你有大量的股票,但典型的查询只要求少数股票,最合理的方法是使用股票名称作为分区键,正如我所说,数据作为排序键。这将允许您有效地 Query
一只特定股票的日期范围 - 如果您需要 3 只不同的股票,您将需要做 3 Query
秒(您可以而且应该并行进行! ) 但这些查询中的每一个都将是高效的,您只需为检索到的实际数据付费,无需任何 post-过滤。
如果有大量不同的日期(例如,您将数据保持在 1 秒分辨率),您的分区可能会变得很大,出于各种原因,不建议这样做。在这种情况下,您可以通过一些粗略的时间 window 将每个分区拆分为多个分区。例如,不是为股票 "GOOG" 设置一个巨大的分区,而是使用一个分区 "GOOG Nov 2019"、一个 "GOOG Dec 2019" 等。当您查询一个小的日期范围时,您会知道具体是哪个分区你需要阅读。但是当查询跨度超过一个月时,您将需要查询多个这样的分区。请注意,非常大的查询将读取(和 return)大量数据,因此会非常昂贵,因此您可能只希望在大型分析作业中执行此操作。
我想使用 DynamoDB 来存储历史股票收盘价。
我的商店将有一些存货,并随着需求的变化增加到更多存货。
我想我会有一个 table,其中唯一的键是 "DATE"
,格式为 YYYY-MM-DD
。
这意味着 table 中的每个项目都有一个 date
键和几个 { TICKER = CLOSING_VALUE }
给定日期的查询也将按所需股票代码的子集进行过滤,例如["INTC", "AAPL"]
.
我有点困惑,因为这个键应该同时用作分区键和排序键。
我应该如何查询以检索给定日期范围内的股票代码子集?
更新:
我正在创建table...
{
AttributeDefinitions: [
{
AttributeName: Date,
AttributeType: S
}
],
TableName: "Historic",
KeySchema: [
{
AttributeName: Date,
KeyType: HASH
}
]
}
以及查询:
{
table_name: "Historic",
projection_expression: "USD,CAD",
filter_expression: "#k between :val1 and :val2",
expression_attribute_names: { "#k" => "Date" },
expression_attribute_values: {
":val1" => "2019-12-01",
":val2" => "2020-01-10"
}
}
我得到一个错误:
Aws::DynamoDB::Errors::ValidationException: Either the KeyConditions or KeyConditionExpression parameter must be specified in the request.
您不能按 - 或 有效地 检索范围 - 分区键排序,您只能按排序键排序。要了解原因,您需要了解 DynamoDB 如何存储其数据。
"partition key" 在 CreateTable operation 中也被称为 "hash key" - 实际上它就像散列中的键一样工作 table:DynamoDB 在这个键,并使用结果数,决定它的大集群的哪个节点应该拥有这个分区。这种方法允许在集群中分布 table,但它不可能 有效地检索按其键排序的不同分区。 "Scan" 操作将 return 分区以看似随机的顺序排列(它们很可能按其键的哈希函数排序),并且不可能有效地仅扫描一系列分区键。这样做可能效率低下 - 通过扫描整个 table 和 过滤 只是您想要的分区。如果我理解正确的话,这就是你想要做的。但这只对小型数据库有意义 - 你会这样吗?
如您所见,密钥的另一个组成部分是 "sort key"。在一个分区内,在一个节点中,该分区中的不同项目按 "sort key" 顺序保持顺序排序。这允许 DynamoDB 有效地检索按此顺序排序的它们,或者有效地仅检索这些排序键的范围 - Query
请求可以完成这两项工作。
因此,要实现您想要的效果,您需要将日期作为 排序键,而不是分区键。如何进行其余数据建模取决于您的典型查询:
如果你有大量的股票,但典型的查询只要求少数股票,最合理的方法是使用股票名称作为分区键,正如我所说,数据作为排序键。这将允许您有效地 Query
一只特定股票的日期范围 - 如果您需要 3 只不同的股票,您将需要做 3 Query
秒(您可以而且应该并行进行! ) 但这些查询中的每一个都将是高效的,您只需为检索到的实际数据付费,无需任何 post-过滤。
如果有大量不同的日期(例如,您将数据保持在 1 秒分辨率),您的分区可能会变得很大,出于各种原因,不建议这样做。在这种情况下,您可以通过一些粗略的时间 window 将每个分区拆分为多个分区。例如,不是为股票 "GOOG" 设置一个巨大的分区,而是使用一个分区 "GOOG Nov 2019"、一个 "GOOG Dec 2019" 等。当您查询一个小的日期范围时,您会知道具体是哪个分区你需要阅读。但是当查询跨度超过一个月时,您将需要查询多个这样的分区。请注意,非常大的查询将读取(和 return)大量数据,因此会非常昂贵,因此您可能只希望在大型分析作业中执行此操作。