如何使用DynamoDB进行基本聚合?

49

如何在DynamoDB中实现聚合?MongoDB和Couchbase支持MapReduce。

假设我们正在构建一个技术博客,在这个博客中用户可以发布文章,且文章可以被标记。

user
{
    id : 1235,
    name : "John",
    ...
}

article
{
    id : 789,
    title: "dynamodb use cases",
    author : 12345 //userid
    tags : ["dynamodb","aws","nosql","document database"]
}

在用户界面上,我们想要显示当前用户的标签及其相应计数。

如何实现以下聚合?

{
    userid : 12,
    tag_stats:{
        "dynamodb" : 3,
        "nosql" : 8
    }
}

我们将通过rest api提供此数据,并且会频繁调用。就像这些信息显示在应用程序的主页面上。

  • 我想到可以提取所有文档并在应用程序级别进行聚合。但我觉得我的读取容量单位会耗尽。
  • 可以使用EMR,redshift,bigquery,aws lambda等工具。但我认为这些是用于数据仓库的目的。

我想了解其他更好的实现相同目的的方法。 人们如何在选择dynamodb作为主要数据存储并考虑成本和响应时间的情况下实现这些动态简单查询。

3个回答

60
长话短说:Dynamo不支持此功能。它并非为此用例而构建,而是旨在快速访问数据并具有低延迟性。它根本不支持任何聚合功能。
你有三个主要选择:
  • 将DynamoDB数据导出到RedshiftEMR Hive。然后,您可以对陈旧的数据执行SQL查询。这种方法的好处是仅消耗一次RCU,但您将使用过时的数据。
  • 使用DynamoDB连接器与Hive直接查询DynamoDB。同样,您可以编写任意SQL查询,但在这种情况下,它将直接访问DynamoDB中的数据。缺点是每次查询都会消耗读取容量。
  • 使用DynamoDB Streams在单独的表中维护聚合数据。例如,您可以将UserId作为分区键,将标签和计数作为属性的嵌套映射表。在原始数据更新时,DynamoDB Streams将在Lambda函数或主机上执行某些代码以更新聚合表。这是最经济实惠的方法,但您需要为每个新查询实现额外的代码。
当然,您可以在应用程序级别提取数据并在那里进行聚合,但我不建议这样做。除非您有一个小表,否则您需要考虑限流,仅使用部分预配容量(例如,您想要使用RCU的20%进行聚合而不是100%),以及如何在多个工作程序之间分配您的工作。
Redshift和Hive都已经知道如何做到这一点。 Redshift在执行查询时依靠多个工作节点,而Hive基于Map-Reduce。此外,Redshift和Hive都可以使用预定义的RCU吞吐量百分比。

8

DynamoDB是纯键/值存储,不支持开箱即用的聚合。

如果您真的想使用DynamoDB进行聚合,这里有一些提示。

对于您的特定情况,假设我们有一个名为articles的表。要进行聚合,我们需要一个额外的表user-stats,其中包含userIdtag_starts

  1. articles表上启用DynamoDB流
  2. 创建一个新的lambda函数user-stats-aggregate,该函数订阅了文章DynamoDB流,并在articles表上的每个创建/更新/删除操作上接收OLD_NEW_IMAGES。
  3. Lambda将执行以下逻辑
  • 如果没有旧图像,请获取当前标记,并针对此用户在数据库中的每次出现将其增加1。(请记住,此用户可能在user-stats中没有初始记录)
  • 如果存在旧图像,请查看是否添加或删除标记,并针对接收到的每个受影响标记应用更改+1或-1,具体取决于情况。
  1. 提供检索这些用户统计数据的API服务。

通常可以使用DynamoDB流、用于执行聚合的lambda和保留不同粒度的汇总结果的额外表(分钟、小时、天、年等)来进行DynamoDB中的聚合。

这样可以在不需要针对每个请求即时执行聚合的情况下,提供接近实时的聚合,并且您可以查询聚合数据。


-1

使用lambda中的scan()和query()可以进行基本聚合。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接