Я довольно новичок в базе данных NoSQL, и у меня обычно нет проблемы, но в моем последнем мобильном приложении я пытаюсь использовать DynamoDB от Amazon, и я ударил стену.Amazon DynamoDB (отношения «многие ко многим»)
Как правило, у меня нет проблем, если таблица содержит уникальные одиночные записи. Однако, если таблица содержит список элементов, связанных с определенным атрибутом, я не уверен, как правильно получить/запросить данные.
Например, внизу находится таблица. Мы будем называть его AWS_DDB_SESSIONS. Он содержит всю информацию о пользовательских сессиях (где SessionID является ключевым хэшем):
Предположит, что данные таблицы представлены следующим образом: SessionID (хэш), время_запуск, конечный момент, USEREMAIL
TableName: AWS_DDB_SESSIONS "AAADFR101", "01:10:00.000Z", "11:10:00.000Z", "[email protected]" "BBBLWL102", "12:20:00.000Z", "18:20:00.000Z", "[email protected]" "CCCUFE103", "03:00:00.000Z", "03:30:00.000Z", "[email protected]"
Я могу легко получить одну запись, если я укажу значение хэш-ключа (SessionID). Например, если я хотел первый элемент в списке (AAADFR101), я бы просто сделать «GetItem» запрос с указанным SessionID:
Amazon's Java SDK PseudoCode: AmazonSDK.API.Table.getItem("AAADFR101"); The SQL equilavent is: select * from AWS_DDB_SESSIONS where SessionID='AAADFR101'; Expected Results: "AAADFR101", "01:10:00.000Z", "11:10:00.000Z", "[email protected]"
Однако, если я хочу, чтобы получить все сеансы связаны с «[email protected]», я понятия не имею, что делать.
Amazon's Java SDK PseudoCode: // Create a Condition... Condition userEmailCondition = new Condition() .withComparisonOperator(ComparisonOperator.EQ.toString()) .withAttributeValueList(new AttributeValue().withS("[email protected]")); // Create the Map of Conditions... Map userEmailConditionMap = new HashMap(); userEmailConditionMap.put("userEmail", userEmailCondition); QueryRequest qRequest = new QueryRequest().withTableName("AWS_DDB_SESSIONS") .withKeyConditions(userEmailConditionMap); QueryResult = AmazonSDK.API.Table.query(qCondition); // NOTE: It errors here because the query doesn't contain the "SessionID" // value within the query(which is the primary key/hash for this table). The SQL equilavent is: select * from AWS_DDB_SESSIONS where UserID="[email protected]"; Expected Results: "AAADFR101", "01:10:00.000Z", "11:10:00.000Z", "[email protected]" "CCCUFE103", "03:00:00.000Z", "03:30:00.000Z", "[email protected]"
Как уже упоминалось выше, псевдо-код Java не работает, потому что DynamoDB API Amazon требует, чтобы первичный ключ (SessionID) при выполнении запроса. Даже если вы изменили схему таблицы DynamoDB, чтобы использовать хэш-ключ (SessionID) и диапазон (UserEmail), вам это нехорошо. По сути, вы сталкиваетесь с той же проблемой.
Я попытался придумать некоторые альтернативные решения, но, похоже, я возвращаюсь к одной и той же проблеме независимо от того, как я к ней подхожу.
Вариант № 1 Первый вариант, который я думал, было добавить еще один атрибут, который был уникальный идентификатор. Таким образом, вы бы изменить схему:
Original Schema: SessionID(hash), StartTime, StopTime, UserEmail New Table Schema: RecordID(hash), SessionID, StartTime, StopTime, UserEmail
Это создает таблицу, аналогичную тот, что вы будете использовать в реляционных базах данных (RDB). Тем не менее, он страдает от первоначальной проблемы неспособности запросить UserEmail.
Вариант № 2 После некоторых онлайн-исследований, было заявлено, что вы могли бы разбить таблицу на меньшие таблиц на основе различных атрибутов (USEREMAIL). Таким образом, для каждого пользователя можно создать таблицу для хранения своей информации сеанса в Следовательно, наш первоначальный образец будет разделен на таблицы со следующими данными:.
TableName: [email protected] "BBBLWL102", "12:20:00.000Z", "18:20:00.000Z" TableName: [email protected] "AAADFR101", "01:10:00.000Z", "11:10:00.000Z" "CCCUFE103", "03:00:00.000Z", "03:30:00.000Z"
В некоторых случаях этот подход рекомендуется, потому что это будет подталкивать вас в направлении удаления избыточных данных (UserEmail), и это может снизить ваши затраты, поскольку оно сканирует меньше данных при запросе таблиц. Но это создает проблему масштабируемости. Если у вас есть 5 человек, использующих ваше приложение, тогда вам будет только 5 таблиц, о которых стоит беспокоиться. Однако, если ваша пользовательская база вырастет до 1000, 100K или 1 миллион, тогда у вас будет сумасшедшее количество столов для отслеживания.Поэтому я не уверен, что это лучший подход.
Вариант № 3 Я пытался добавить некоторые индексы для атрибутов, которые я думал, были важны, но это не сработало, как я думал, и все еще была та же исходная задача.
Вариант № 4 Изменение хэш-ключ из SessionID, к USEREMAIL, а затем использовать SessionID в качестве ключа диапазона. Но кажется, что это может не работать при определенных обстоятельствах, например, когда эти значения перекрываются, имеют разные поля атрибутов или атрибуты имеют одинаковое значение. Например, если у Джона Доу был другой сеанс с идентификатором «AAADFR101», он заменил бы существующую запись вместо двух записей с подобной информацией. Вы можете преодолеть эту проблему, добавив новый атрибут (RecordID) и использовать его как первичный ключ (значение хэша). Тем не менее, вы вернулись к исходной проблеме, если попытаетесь выполнить запрос.
Ugh ... У меня начинает болеть голова. Может кто-то указать мне в правильном направлении.
Спасибо заранее,
-Randy
Я не понимаю, что у вас есть с Альтернативой 4. SessionId должен быть уникальным в глобальном масштабе? Вот почему в старой схеме вы используете sessionId как hashkey. Дайте мне знать, если я имею в виду ... –
Альтернатива 4 выглядит хорошо. Использование customerId как hashkey очень распространено. Также вам нужно убедиться, что ваш sessionId уникален (используйте генератор случайных идентификаторов?). –
Спасибо за комментарий Эрбен. Есть 2 проблемы, которые у меня есть с решением № 4. –