Amazon DynamoDB(多对多关系)
Amazon DynamoDB (many-to-many relationships)
我对 NoSQL 数据库还很陌生,通常没有问题,但在我最新的移动应用程序中,我尝试使用亚马逊的 DynamoDB,但遇到了困难。
一般来说,如果 table 包含唯一的单个条目,我不会有任何问题。但是,如果 table 包含与特定属性关联的项目列表,我不确定如何正确地 retrieve/query 数据。
例如下面是一个table。我们称它为AWS_DDB_SESSIONS。它包含有关用户会话的所有信息(其中 SessionID 是哈希键):
假设table数据表示如下:SessionID(hash), StartTime, StopTime, UserEmail
Table姓名:AWS_DDB_SESSIONS
"AAADFR101"、“01:10:00.000Z”、“11:10:00.000Z”、"john.doe@mydomain.com"
"BBBLWL102", "12:20:00.000Z", "18:20:00.000Z", "jane.smith@mydomain.com"
"CCCUFE103"、“03:00:00.000Z”、“03:30:00.000Z”、"john.doe@mydomain.com"
如果指定散列键值 (SessionID),我可以轻松获得单个条目。例如,如果我想要列表中的第一项 (AAADFR101),我只需使用指定的 SessionID 发出 "getItem" 请求:
亚马逊的 Java SDK 伪代码:
AmazonSDK.API.Table.getItem("AAADFR101");
SQL 等价物是:
select * 来自 AWS_DDB_SESSIONS 其中 SessionID='AAADFR101';
预期成绩:
"AAADFR101", "01:10:00.000Z", "11:10:00.000Z", "john.doe@mydomain.com"
但是,如果我想获得与 "john.doe@mydomain.com" 关联的所有会话,我不知道该怎么做。
亚马逊的 Java SDK 伪代码:
// 创建条件...
条件 userEmailCondition = new Condition()
.withComparisonOperator(ComparisonOperator.EQ.toString())
.withAttributeValueList(new AttributeValue().withS("john.doe@mydomain.com"));
// 创建条件映射...
映射 userEmailConditionMap = new HashMap();
userEmailConditionMap.put("userEmail", userEmailCondition);
QueryRequest qRequest = new QueryRequest().withTableName("AWS_DDB_SESSIONS")
.withKeyConditions(userEmailConditionMap);
QueryResult = AmazonSDK.API.Table.query(qCondition);
// 注意:这里出错是因为查询不包含 "SessionID"
// 查询中的值(这是此 table 的主要 key/hash)。
SQL 等价物是:
select * 来自 AWS_DDB_SESSIONS 其中 UserID="john.doe@mydomain.com";
预期成绩:
"AAADFR101"、“01:10:00.000Z”、“11:10:00.000Z”、"john.doe@mydomain.com"
"CCCUFE103"、“03:00:00.000Z”、“03:30:00.000Z”、"john.doe@mydomain.com"
如上所述,Java 伪代码不起作用,因为 Amazon 的 DynamoDB API 在您执行查询时需要主键 (SessionID)。即使您将 DynamoDB table 的架构更改为使用散列键 (SessionID) 和范围 (UserEmail),也没有用。本质上,你 运行 遇到了同样的问题。
我试图想出一些替代解决方案,但无论我如何处理它,我似乎都会回到同样的问题。
选择#1
我想到的第一个替代方案是添加另一个属性,它是一个唯一标识符。所以你会改变模式:
原始架构:
SessionID(散列)、StartTime、StopTime、UserEmail
新 Table 架构:
RecordID(哈希)、SessionID、StartTime、StopTime、UserEmail
这将创建一个类似于您将在关系数据库 (RDB) 中使用的 table。但是,它遇到了无法在UserEmail上查询的原始问题。
备选方案 #2
经过一些在线研究后,据说您可以根据各种属性 (userEmail) 将 table 拆分成更小的 table。因此,对于每个用户,您都可以创建一个 table 来存储他们的会话信息。因此,我们的原始样本将被分成 tables,其中包含以下数据:
Table姓名:AWS_DDB_SESSIONS_jane.smith@mydomain.com
"BBBLWL102", "12:20:00.000Z", "18:20:00.000Z"
Table姓名:AWS_DDB_SESSIONS_john.doe@mydomain.com
"AAADFR101", "01:10:00.000Z", "11:10:00.000Z"
"CCCUFE103", "03:00:00.000Z", "03:30:00.000Z"
在某些情况下,建议使用这种方法,因为它会促使您朝着删除冗余数据 (UserEmail) 的方向发展,并且它可能会降低您的成本,因为它在查询 table 时扫描的数据较少。但这似乎会产生可扩展性问题。如果您有 5 个人使用您的应用程序,那么您只需担心 5 tables。但是,如果您的用户群增长到 1000、100K 或 100 万,那么您将有大量的 table 需要跟踪。所以我不确定这是否是最好的方法。
选择#3
我尝试为我认为重要的属性添加一些索引,但它并没有像我想的那样工作,并且仍然有同样的原始问题。
选择#4
将散列键从 SessionID 更改为 UserEmail,然后使用 SessionID 作为范围键。但似乎这在某些情况下可能不起作用,例如当这些值重叠、具有不同的属性字段或属性具有相同的值时。例如,如果 John Doe 有另一个 ID 为 "AAADFR101" 的会话,那么它将覆盖现有条目,而不是有 2 个具有相似信息的条目。您可以通过添加新属性 (RecordID) 并将其用作主键(哈希值)来克服这一挑战。但是,你又回到了原来的问题,你会尝试查询吗。
呃……我的头开始疼了。有人能指出我正确的方向吗?
提前致谢,
-兰迪
欢迎使用 dynamoDB,一个很棒的非关系解决方案!
如果您只想添加通过电子邮件搜索的功能,您可以使用全局索引来实现,请参阅 http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html。这将有效地让亚马逊为您保留第二个 table ……所以请考虑双倍的成本,但允许您使用任一键。由于您提到了缩放问题,如果您担心电子邮件的分布,您可以先对它们进行 md5 哈希处理。您可以考虑使用开始或停止时间作为范围键。
您将无法按属性对所有数据进行排序。如果需要,您需要寻找其他解决方案。
我对 NoSQL 数据库还很陌生,通常没有问题,但在我最新的移动应用程序中,我尝试使用亚马逊的 DynamoDB,但遇到了困难。
一般来说,如果 table 包含唯一的单个条目,我不会有任何问题。但是,如果 table 包含与特定属性关联的项目列表,我不确定如何正确地 retrieve/query 数据。
例如下面是一个table。我们称它为AWS_DDB_SESSIONS。它包含有关用户会话的所有信息(其中 SessionID 是哈希键):
假设table数据表示如下:SessionID(hash), StartTime, StopTime, UserEmail
Table姓名:AWS_DDB_SESSIONS "AAADFR101"、“01:10:00.000Z”、“11:10:00.000Z”、"john.doe@mydomain.com" "BBBLWL102", "12:20:00.000Z", "18:20:00.000Z", "jane.smith@mydomain.com" "CCCUFE103"、“03:00:00.000Z”、“03:30:00.000Z”、"john.doe@mydomain.com"
如果指定散列键值 (SessionID),我可以轻松获得单个条目。例如,如果我想要列表中的第一项 (AAADFR101),我只需使用指定的 SessionID 发出 "getItem" 请求:
亚马逊的 Java SDK 伪代码: AmazonSDK.API.Table.getItem("AAADFR101"); SQL 等价物是: select * 来自 AWS_DDB_SESSIONS 其中 SessionID='AAADFR101'; 预期成绩: "AAADFR101", "01:10:00.000Z", "11:10:00.000Z", "john.doe@mydomain.com"
但是,如果我想获得与 "john.doe@mydomain.com" 关联的所有会话,我不知道该怎么做。
亚马逊的 Java SDK 伪代码: // 创建条件... 条件 userEmailCondition = new Condition() .withComparisonOperator(ComparisonOperator.EQ.toString()) .withAttributeValueList(new AttributeValue().withS("john.doe@mydomain.com")); // 创建条件映射... 映射 userEmailConditionMap = new HashMap(); userEmailConditionMap.put("userEmail", userEmailCondition); QueryRequest qRequest = new QueryRequest().withTableName("AWS_DDB_SESSIONS") .withKeyConditions(userEmailConditionMap); QueryResult = AmazonSDK.API.Table.query(qCondition); // 注意:这里出错是因为查询不包含 "SessionID" // 查询中的值(这是此 table 的主要 key/hash)。 SQL 等价物是: select * 来自 AWS_DDB_SESSIONS 其中 UserID="john.doe@mydomain.com"; 预期成绩: "AAADFR101"、“01:10:00.000Z”、“11:10:00.000Z”、"john.doe@mydomain.com" "CCCUFE103"、“03:00:00.000Z”、“03:30:00.000Z”、"john.doe@mydomain.com"
如上所述,Java 伪代码不起作用,因为 Amazon 的 DynamoDB API 在您执行查询时需要主键 (SessionID)。即使您将 DynamoDB table 的架构更改为使用散列键 (SessionID) 和范围 (UserEmail),也没有用。本质上,你 运行 遇到了同样的问题。
我试图想出一些替代解决方案,但无论我如何处理它,我似乎都会回到同样的问题。
选择#1
我想到的第一个替代方案是添加另一个属性,它是一个唯一标识符。所以你会改变模式:
原始架构: SessionID(散列)、StartTime、StopTime、UserEmail 新 Table 架构: RecordID(哈希)、SessionID、StartTime、StopTime、UserEmail
这将创建一个类似于您将在关系数据库 (RDB) 中使用的 table。但是,它遇到了无法在UserEmail上查询的原始问题。
备选方案 #2
经过一些在线研究后,据说您可以根据各种属性 (userEmail) 将 table 拆分成更小的 table。因此,对于每个用户,您都可以创建一个 table 来存储他们的会话信息。因此,我们的原始样本将被分成 tables,其中包含以下数据:
Table姓名:AWS_DDB_SESSIONS_jane.smith@mydomain.com "BBBLWL102", "12:20:00.000Z", "18:20:00.000Z" Table姓名:AWS_DDB_SESSIONS_john.doe@mydomain.com "AAADFR101", "01:10:00.000Z", "11:10:00.000Z" "CCCUFE103", "03:00:00.000Z", "03:30:00.000Z"
在某些情况下,建议使用这种方法,因为它会促使您朝着删除冗余数据 (UserEmail) 的方向发展,并且它可能会降低您的成本,因为它在查询 table 时扫描的数据较少。但这似乎会产生可扩展性问题。如果您有 5 个人使用您的应用程序,那么您只需担心 5 tables。但是,如果您的用户群增长到 1000、100K 或 100 万,那么您将有大量的 table 需要跟踪。所以我不确定这是否是最好的方法。
选择#3
我尝试为我认为重要的属性添加一些索引,但它并没有像我想的那样工作,并且仍然有同样的原始问题。
选择#4
将散列键从 SessionID 更改为 UserEmail,然后使用 SessionID 作为范围键。但似乎这在某些情况下可能不起作用,例如当这些值重叠、具有不同的属性字段或属性具有相同的值时。例如,如果 John Doe 有另一个 ID 为 "AAADFR101" 的会话,那么它将覆盖现有条目,而不是有 2 个具有相似信息的条目。您可以通过添加新属性 (RecordID) 并将其用作主键(哈希值)来克服这一挑战。但是,你又回到了原来的问题,你会尝试查询吗。
呃……我的头开始疼了。有人能指出我正确的方向吗?
提前致谢,
-兰迪
欢迎使用 dynamoDB,一个很棒的非关系解决方案!
如果您只想添加通过电子邮件搜索的功能,您可以使用全局索引来实现,请参阅 http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html。这将有效地让亚马逊为您保留第二个 table ……所以请考虑双倍的成本,但允许您使用任一键。由于您提到了缩放问题,如果您担心电子邮件的分布,您可以先对它们进行 md5 哈希处理。您可以考虑使用开始或停止时间作为范围键。
您将无法按属性对所有数据进行排序。如果需要,您需要寻找其他解决方案。