1

Я довольно новичок в базе данных 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

+0

Я не понимаю, что у вас есть с Альтернативой 4. SessionId должен быть уникальным в глобальном масштабе? Вот почему в старой схеме вы используете sessionId как hashkey. Дайте мне знать, если я имею в виду ... –

+0

Альтернатива 4 выглядит хорошо. Использование customerId как hashkey очень распространено. Также вам нужно убедиться, что ваш sessionId уникален (используйте генератор случайных идентификаторов?). –

+0

Спасибо за комментарий Эрбен. Есть 2 проблемы, которые у меня есть с решением № 4. –

ответ

2

Добро пожаловать в dynamoDB, большое нереляционная решение!

Если все, что вы хотите добавить, это возможность поиска по электронной почте, вы можете сделать это, используя глобальные индексы, см. http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html. Это будет эффективно поддерживать Amazon второй стол для вас ... так что подумайте, удвоьте затраты, но позвольте вам использовать любой ключ. Поскольку вы упоминаете проблемы масштабирования, если вы беспокоитесь о распространении своих электронных писем, вы можете сначала mh5-хэш их. Вы можете использовать время запуска или остановки в качестве ключа диапазона.

Вы не сможете сортировать все свои данные по атрибуту. Если это необходимо, вам нужно будет найти другое решение.

+0

Спасибо за ответ, Arosenber. Таким образом, вы все равно будете использовать DynamoDB, или вы пойдете на решение RDBS, такое как MySQL на EC2 или RDS Amazon? –

+0

Эй, randy, если у вас есть только небольшой набор предметов, разделяющих атрибут, порядка сотни, тогда вы отлично справляетесь с DynamoDB. Если вы хотите делать полные сортировки данных, я бы сказал, что используйте RDS. Это очень прямолинейно, чтобы масштабироваться вверх и вниз, и будет обрабатывать множество данных. – arosenber

+0

Спасибо Arosenber. В ближайшей перспективе DynamoDB может работать. Но я думаю, что в долгосрочной перспективе решение NoSQL не может быть лучшим инструментом для работы. –

Смежные вопросы