如何使用dynamodb实现聚合?Mongodb 和 couchbase 有地图减少支持。
假设我们正在建立一个技术博客,用户可以在其中发布文章。并说文章可以被标记。
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 作为主要数据存储。
长话短说:Dynamo 不支持此功能。它不是为此用例而构建的。它旨在以低延迟快速访问数据。它根本不支持任何聚合功能。
您有三个主要选项:
-
将 DynamoDB 数据导出到 Redshift 或 EMR Hive。然后,您可以对过时的数据执行 SQL 查询。这种方法的好处是它只消耗一次 RCU,但你会坚持使用过时的数据。
-
使用适用于 Hive 的 DynamoDB 连接器并直接查询 DynamoDB。同样,您可以编写任意 SQL 查询,但在这种情况下,它将直接访问 DynamoDB 中的数据。缺点是它会消耗您执行的每个查询的读取容量。
-
使用 DynamoDB 流在单独的表中维护聚合数据。例如,您可以将表 UserId 作为分区键,并将标记和计数作为属性的嵌套映射。每次更新原始数据时,DynamoDB 流都会在主机上执行 Lambda 函数或一些代码来更新聚合表。这是最具成本效益的方法,但您需要为每个新查询实现其他代码。
当然,您可以在应用程序级别提取数据并在那里聚合它,但我不建议这样做。除非您有一个小表,否则您需要考虑限制、仅使用部分预置容量(例如,您希望使用 20% 的 RCU 进行聚合,而不是 100%),以及如何在多个工作线程之间分配工作。
Redshift和Hive都已经知道如何做到这一点。Redshift在执行查询时依赖于多个工作节点,而Hive则基于Map-Reduce。此外,Redshift 和 Hive 都可以使用预定义的 RCU 吞吐量百分比。
Dynamodb 是纯键/值存储,不支持开箱即用的聚合。
如果您真的想使用 DynamoDB 进行聚合,这里有一些提示。
对于您的特定情况,让我们有一个名为articles
的表。 要进行聚合,我们需要一个额外的表user-stats
保存userId
和tag_starts
。
- 在表
articles
上启用了 DynamoDB 流 - 创建一个新的 lambda 函数
user-stats-aggregate
该函数订阅文章 DynamoDB 流,并在表articles
的每个创建/更新/删除操作中接收OLD_NEW_IMAGES。 - Lambda 将执行以下逻辑
- 如果没有旧映像,则获取当前标记,并在该用户的数据库中每次出现时增加 1。(请记住,可能没有
user-stats
此用户的初始记录) - 如果有旧图像,请查看是否添加或删除了标签,并根据收到的用户的每个受影响标签的情况应用更改 +1 或 -1。
- 站立一个 API 服务来检索这些用户统计信息。
通常,DynamoDB 中的聚合可以使用 DynamoDB 流、用于执行聚合的 lambda 和额外的表来完成,以保持不同粒度的聚合结果。分钟,小时,天,年...
这带来了近乎实时的聚合,而无需根据每个请求即时执行,您可以查询聚合数据。
基本聚合可以在lambda中使用scan()和query()来完成。