Amazon web services 查询多值属性的DynamoDB表/索引模式设计

Amazon web services 查询多值属性的DynamoDB表/索引模式设计,amazon-web-services,amazon-dynamodb,dynamodb-queries,Amazon Web Services,Amazon Dynamodb,Dynamodb Queries,我正在构建一个DynamoDB应用程序,它最终将服务于数百万用户。目前,应用程序的项目架构很简单: { userId: "08074c7e0c0a4453b3c723685021d0b6", // partition key email: "foo@foo.com", ... other attributes ... } 当一个新用户注册时,或者如果一个用户想通过电子邮件地址找到另一个用户,我们需要通过电子邮件而不是用户ID查找用户。对于当前的模式,这很简单:只需使用一个全局二

我正在构建一个DynamoDB应用程序,它最终将服务于数百万用户。目前,应用程序的项目架构很简单:

{ 
  userId: "08074c7e0c0a4453b3c723685021d0b6",  // partition key
  email: "foo@foo.com",
  ... other attributes ...
}
当一个新用户注册时,或者如果一个用户想通过电子邮件地址找到另一个用户,我们需要通过电子邮件而不是用户ID查找用户。对于当前的模式,这很简单:只需使用一个全局二级索引,并将电子邮件作为分区键

但是我们希望为每个用户启用多个电子邮件地址,而DynamoDB操作不支持列表类型的KeyConditionExpression。因此,我正在权衡几种选择,以避免每次用户注册或希望通过电子邮件地址找到另一个用户时进行昂贵的扫描操作

下面是我计划更改的内容,以便为每个用户启用额外的电子邮件。这是一个好方法吗?有更好的选择吗

添加一个排序键列,例如itemTypeAndIndex,以允许每个用户ID有多个项目。 { 用户ID:08074c7e0c0a4453b3c723685021d0b6,//分区键 itemTypeAndIndex:main,//排序键 电邮:foo@foo.com, …其他属性。。。 }

如果用户添加第二封、第三封等电子邮件,则为每封电子邮件添加一个新项目,如下所示: { 用户ID:08074c7e0c0a4453b3c723685021d0b6,//分区键 itemTypeAndIndex:Email-2,//排序键 电邮:bar@bar.com //没有更多属性 }

将电子邮件作为分区键的同一全局二级索引仍然可以用于查找主电子邮件地址和非主电子邮件地址

如果用户想要更改其主要电子邮件地址,我们将交换主要和非主要项目中的电子邮件值。现在DynamoDB支持,这样做会比以前更安全

如果我们需要删除一个用户,我们必须删除该用户ID的所有项目。如果我们需要合并两个用户,那么我们必须合并该用户ID的所有项

同样的方法,具有相同userId但不同排序键的新项可以用于需要可查询的其他1-user-has-multi-values数据


这是一个好方法吗?有更好的方法吗?

Justin,对于搜索属性,我强烈建议不要使用DynamoDB。我不是说,你不能做到这一点。然而,我看到一些问题,最终会在你的道路上,如果你走这条路的根

对电子邮件id使用排序键将导致为同一用户创建重复记录,即,如果用户已注册5封电子邮件,则意味着表中有5条记录具有相同的架构和属性,但电子邮件id属性除外。 如果将来出现一个新的用例,您现在还想基于一些其他属性搜索一个用户,例如手机号码,假设一个用户可能有多个手机号码,该怎么办 DynamoDB有一个可以为表创建的表,即5。 因此,随着搜索条件用例的增加,此解决方案将很容易成为系统的瓶颈。因此,您的系统可能无法很好地扩展

据我所知,我可以建议一些选项,您可以根据您的需求/预算,使用数据库组合来解决此问题

备选案文1。DynamoDB作为主存储器,AWS Elasticsearch作为辅助存储器[首选]

将用户记录存储在DynamoDB表中,我们称之为UserTableas,当用户注册时。 在UserTable表上启用DynamoDB表流。 构建一个AWS Lambda函数,该函数从表的流中读取数据,并将记录保存在AWS Elasticsearch中。 现在在您的应用程序中,使用DynamoDB从id获取用户记录。对于所有其他搜索标准,如搜索emailId、电话号码、邮政编码、位置等,从AWS Elasticsearch获取记录。AWS Elasticsearch默认为记录的所有属性编制索引,因此您可以在延迟毫秒内搜索任何字段

备选案文2。使用AWS Aurora[不太受欢迎的解决方案]

如果你的应用程序有一个数据相关的关系用例,你可以考虑这个选项。我只是想说,Aurora是一个SQL数据库。 由于这是一个关系存储,您可以选择在多个表中组织记录,并根据这些表的主键将它们连接起来

我将建议第一个选项,如下所示:

DynamoDB将为您的应用程序提供持久、高可用、低延迟的主存储。 AWS Elasticsearch将充当辅助存储,它也是持久、可扩展和低延迟的存储。 使用AWS Elasticsearch,您可以在表上运行任何搜索查询。您还可以对数据进行分析。开箱即用,可用于在仪表板上绘制分析数据,如用户增长趋势、特定位置的用户数量、基于城市/州/国家的用户分布等 使用DynamoDB streams和AWS Lambda,您将[在几毫秒内]近乎实时地同步这两个数据库 你的申请将 具有可扩展性,并且可以进一步增强搜索功能,以便对多级属性进行过滤。[一个这样的例子:搜索属于给定城市的所有用户]
话虽如此,现在我将由你们来决定。贾斯汀,为了搜索属性,我强烈建议不要使用DynamoDB。我不是说,你可以做到这一点。然而,我看到了一些问题,这些问题最终会出现在你的道路上,如果你这样做的话。@mango-你预见到了什么问题?我不小心在评论中写下了我的答案。我在答案部分添加了一个详细的答案。我希望这会有所帮助。如果您已经承诺将DynamoDB用作主数据存储,将Elastic用作辅助数据存储,请尝试Rockset。与elastic相比的主要优势是,您可以像lambda一样获得完整的SQL和自动缩放/无服务器。Rockset不是事务性的,不支持删除/修改数据,但如果您只想快速查询,Rockset将支持这一点。