【问题标题】:How to select items in date range in DynamoDB如何在 DynamoDB 中选择日期范围内的项目
【发布时间】:2021-06-01 09:59:16
【问题描述】:

如何选择给定日期范围内的所有项目?

SELECT * FROM GameScores where createdAt >= start_date && createAt

我想进行这样的查询。是否需要创建全局二级索引?

我试过了

public void getItemsByDate(Date start, Date end) {
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    String stringStart = df.format(start);
    String stringEnd = df.format(end);

    ScanSpec scanSpec = new ScanSpec();
    scanSpec.withFilterExpression("CreatedAt BETWEEN :from AND :to")
            .withValueMap(
                    new ValueMap()
                            .withString(":from", stringStart)
                            .withString(":to", stringEnd));

    ItemCollection<ScanOutcome> items = null;
    items = gamesScoresTable.scan(scanSpec);
}

但这不起作用,我得到的结果比预期的要少。

【问题讨论】:

  • 你的密钥结构是什么样的,你的数据是什么样的?基于这些信息,我们只能说:视情况而定。
  • 我不知道 java sdk 是如何工作的,但是您正在扫描,所以结果很可能会被分页,这可以解释为什么您得到的结果比预期的要少。跨度>

标签: java amazon-web-services amazon-dynamodb


【解决方案1】:

我可以回答您的问题,但要提出任何真正的解决方案,我需要查看您的数据的一般形式,以及您的 GameScore 的主键是什么。

TLDR;

设置您的表,以便您可以通过查询而不是扫描和过滤器来检索数据,然后创建索引以支持较少使用的访问模式并提高查询灵活性。由于在提供完整(或者虽然没有那么快,部分)主键(即使用查询)时读取速度非常快,因此当表结构由应用程序的访问模式驱动时,DynamoDB 是最佳选择。

在设计您的表格时,请牢记NoSQL design best practicesbest practices for querying and scanning,从长远来看它会带来好处。

说明

问题 1

如何选择给定日期范围内的所有项目?

为了回答这个问题,我想进一步分解这个问题。让我们开始:如何选择所有项目?

这个,你已经完成了。扫描是检索表中所有项目的好方法,除非您将所有项目都放在一个分区中,否则它是检索表中所有项目的唯一方法。当您必须通过未知键访问数据时,扫描会很有帮助。

但是,扫描有局限性,并且随着您的表格大小的增加,它们会在性能和成本方面付出代价。单次扫描最多只能检索单个分区的 1MB 数据,并且以该分区的读取容量为上限。当扫描达到任一限制时,连续扫描将按顺序进行。这意味着对大表的扫描可能需要多次往返。

最重要的是,通过扫描,您会根据项目的大小消耗读取容量,无论返回多少(或很少)数据。如果您只在 ProjectionExpression 中请求少量属性,而您的 FilterExpression 消除了表中 90% 的项目,那么您仍然需要付费阅读整个表。

您可以使用并行扫描优化扫描性能,但如果您需要对应用程序中频繁发生的访问模式进行整个表扫描,则应考虑重组表。 More about scans.

现在让我们看看:如何根据某些条件选择所有项目?

根据某些条件(在您的情况下为SELECT * FROM GameScores where createdAt &gt;= start_date &amp;&amp; createAt &lt;=end_date)完成检索数据的理想方法是查询基表(或索引)。为此,请根据文档:

您必须提供分区键属性的名称和该属性的单个值。查询返回具有该分区键值的所有项目。

如文档所述,查询分区将返回其所有值。如果您的 GameScores 表具有 GameName 的分区键,那么对 GameName = PacMan 的查询将返回具有该分区键的所有项目。但是,此查询不会捕获其他 GameName 分区。

如果您需要更深入的查询:

您可以选择提供排序键属性并使用比较运算符来优化搜索结果。

这里有一个list,您可以在排序键中使用所有可能的比较运算符。在这里,您可以在查询操作的 KeyConditionExpression 中利用 between 比较运算符。类似:GameName = PacMan AND createdAt BETWEEN time1 AND time2 将起作用,如果 createdAt 是您正在查询的表或索引的排序键。

如果不是排序键,你可能会得到第二个问题的答案。

问题 2

我需要创建一个全局二级索引吗?

让我们开始吧:我需要创建索引吗?

如果您的基表数据结构不适合您的应用程序的某些访问模式,您可能需要这样做。但是,在 DynamoDB 中,数据的非规范化也支持更多的访问模式。我建议您观看this video,了解如何构建数据。

继续:我需要创建 GSI 吗?

GSI 不支持强读取一致性,因此如果需要,您需要使用本地二级索引 (LSI)。但是,如果您已经创建了基表,则无法创建 LSI。两者之间的另一个区别是主键:GSI 可以有不同的分区和排序键作为基表,而 LSI 只能在排序键上有所不同。 More about indexes.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多