I have a question. I m pretty new to DynamoDB but have been working on large scale aggregation on SQL databases for a long time.
Suppose you have a table called GamePoints (PlayerId, GameId, Points) and would like to create a ranking table Rankings (PlayerId, Points) sorted by points.
This table needs to be updated on an hourly basis but keeping the previous version of its contents is not required. Just the current Rankings.
The query will always be give me the ranking table (with paging).
The GamePoints table will get very very large over time.
Questions:
Is this the best practice schema for DynamoDB ? How would you do this kind of aggregation?
Thanks
答案 0 :(得分:2)
您可以在GamePoints表上启用DynamoDB Stream。您可以从流中读取流记录以维护物化视图,包括聚合,如排名表。在GamePoints表上设置StreamViewType = NEW_IMAGE,并设置Lambda function以消耗流中的流记录,并使用原子计数器更新每个玩家的点数(UpdateItem,HK = player_id,UpdateExpression =“ADD Points #stream_record_points”, ExpressionAttributeValues = {“#stream_record_points”:[将流记录中的值放在此处。]})。由于Rankings表的哈希键仍然是玩家ID,你可以每小时对Rankings表进行全表扫描,以获得n个最高玩家,或所有玩家并进行排序。
但是,考虑到字段的大小(player_id和点数可能不超过100个字节),由Lambda函数更新的内存缓存同样可以用于跟踪播放器的降序列表及其实时总点数。最后,如果您的应用程序需要有状态地处理Stream记录,您可以使用Kinesis Client Library与应用程序服务器上的DynamoDB Streams Kinesis Adapter结合使用,以获得与将Lambda函数订阅到GamePoints表的流相同的效果
答案 1 :(得分:0)
PutItem
可以帮助您根据用例实现持久性逻辑:
PutItem创建一个新项目,或用新项目替换旧项目。 如果项目与新项目具有相同的主键 存在于指定的表中,新项完全替换了 现有项目。您可以执行条件放置操作(添加新操作) item(如果具有指定主键的项目不存在)或替换 现有项目是否具有某些属性值。资源: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
在查询数据方面,如果您确定要阅读整个Ranking
表,我建议您通过多次读取操作来完成最小可接受页面大小这样您就可以充分利用预配置的吞吐量。有关详细信息,请参阅以下指南:
您可以使用以下方法,而不是使用大型扫描操作 最小化扫描对桌面配置的影响的技术 吞吐量。
缩小页面大小
因为扫描操作会读取整个页面(默认情况下为1 MB),所以 通过设置较小的页面可以减少扫描操作的影响 尺寸。扫描操作提供您可以使用的限制参数 设置您的请求的页面大小。 每个扫描或查询请求 具有较小的页面大小使用较少的读取操作并创建一个 "暂停"在每个请求之间。 例如,如果每个项目都是4 KB和 您将页面大小设置为40个项目,然后将使用查询请求 只有40个强烈一致的读操作或最终20个 一致的读操作。较大数量的较小扫描或查询 操作将允许您的其他关键请求成功 节流。
隔离扫描操作
DynamoDB旨在实现轻松的可扩展性。结果,一个应用程序 可以为不同的目的创建表,甚至可能重复 几个表中的内容。您想要在表上执行扫描 这不是关键任务"任务关键"交通。一些应用 通过在两个表之间每小时轮换一次流量来处理此负载 - 一个 用于关键流量,一个用于簿记。其他应用可以 通过在两个表上执行每次写操作来完成此操作:"任务关键" 桌子和阴影"表
您还可以按GameId
(例如Ranking_GameId)对表格进行细分,以便更均匀地分发数据,并在预配置吞吐量方面为您提供更多粒度。
答案 2 :(得分:0)
一种简单的方法是使用DynamoDb的HashKey和Sort键。例如,HashKey是GameId,Sort键是Score。然后,您使用降序排序和限制查询表,以获得O(1)中的实时顶级玩家。
要获得给定玩家的等级,您可以使用与上述相同的技术:您获得O(1)中的前1000个分数,然后使用BinarySearch找到玩家在O中排名前1000的等级( log n)在您的应用程序服务器上。
如果用户的排名为1000,则可以指定此用户的排名为1000+。您显然也可以将1000更改为更大的数字(例如100,000)。
希望这有帮助。
亨利