Как вы отслеживаете отношения в NoSQL?

Я пытаюсь выяснить эквивалент внешних ключей и индексов в NoSQL KVP или базах данных документов. Поскольку нет стержневых таблиц (для добавления ключей, отмечающих связь между двумя объектами), я действительно в тупике относительно того, как вы сможете получить данные таким образом, который был бы полезен для обычных веб-страниц.

скажем, у меня есть пользователь, и этот пользователь оставляет много комментариев по всему сайту. Единственный способ, который я могу придумать, чтобы отслеживать комментарии пользователей, - это

  1. встроить их в объект пользователя (что кажется совершенно бесполезным)
  2. создать и поддерживать user_id:comments значение, содержащее список ключей каждого комментария [comment: 34, comment:197 и т. д... так что я могу принести их по мере необходимости.

однако, взяв второй пример, вы скоро столкнетесь с кирпичной стеной, когда будете использовать ее для отслеживания других вещей, таких как ключ под названием "active_comments", который может содержать 30 миллионов идентификаторов в нем, что делает его стоимость a Тон запросить каждую страницу, чтобы узнать некоторые последние активные комментарии. Он также будет очень склонен к расы-условия столько страниц может попытаться обновить его одновременно.

как я могу отслеживать отношения, подобные приведенным ниже, в базе данных NoSQL?

  • все комментарии пользователя
  • все активные комментарии
  • все сообщения с тегами [keyword]
  • все студенты в клубе - или все клубы студент в

или я думаю об этом неправильно?

4 ответов


все ответы о том, как хранить ассоциации "многие ко многим" в "NoSQL way" сводятся к одному и тому же: избыточное хранение данных.

в NoSQL вы не разрабатываете свою базу данных на основе отношений между сущностями данных. Проектирования базы данных на основе запросов будет работать против него. Используйте те же критерии, которые вы использовали бы для денормализации реляционной базы данных: если для данных более важно иметь когезию (подумайте о значениях, разделенных запятыми список вместо нормализованной таблицы), затем сделайте это таким образом.

но это неизбежно оптимизируется для одного типа запроса (например, комментарии любого пользователя для данной статьи) за счет других типов запросов (комментарии для любой статьи данного пользователя). Если приложению необходимо одинаково оптимизировать оба типа запросов, не следует денормализовывать их. И точно так же вы не должны использовать решение NoSQL, если вам нужно использовать данные реляционным способом.

там риск с денормализацией и избыточностью, что избыточные наборы данных будут выходить из синхронизации друг с другом. Это называется аномалия. При использовании нормализованной реляционной базы данных СУБД может предотвращать аномалии. В денормализованной базе данных или в NoSQL вы несете ответственность за написание кода приложения для предотвращения аномалий.

можно подумать, что для базы данных NoSQL было бы здорово сделать тяжелую работу по предотвращению аномалий для вас. Есть парадигма, которая может это сделать-реляционная парадигма.


  1. user:userid: comments-разумный подход-подумайте об этом как о эквиваленте индекса столбца в SQL с добавленным требованием, чтобы вы не могли запрашивать неиндексированные столбцы.

  2. Это где вам нужно думать о ваших требованиях. Список с 30 миллионами пунктов не является необоснованным, потому что он медленный, но потому что с ним невозможно что-либо сделать. Если ваше реальное требование-отобразить некоторые последние комментарии, Вам лучше сохранение очень короткого списка, который обновляется при добавлении комментария-помните, что NoSQL не требует нормализации. Условия гонки-это проблема со списками в базовом хранилище значений ключей, но обычно ваша платформа поддерживает списки правильно, вы можете сделать что-то с блокировками, или вам на самом деле все равно о неудачных обновлениях.

  3. то же, что и для комментариев пользователей - создайте ключевое слово индекса:posts

  4. больше того же - вероятно, список клубы как собственность студента и индекс на этом поле, чтобы получить всех членов клуба


подход couchDB предлагает испускать правильные классы материала в фазе карты и суммировать его в reduce.. Таким образом, вы можете отобразить все комментарии и испустить 1 для данного пользователя и позже распечатайте только те. Однако для создания постоянных представлений всех отслеживаемых данных в couchDB потребуется много дискового хранилища. кстати, у них также есть эта страница wiki об отношениях:http://wiki.apache.org/couchdb/EntityRelationship.

Riak, с другой стороны, имеет инструмент для сборки родство. Это линк. Вы можете ввести адрес связанного (здесь комментарий) документа в "корневой" документ (здесь пользовательский документ). Есть один трюк. Если он распространяется, он может быть изменен одновременно во многих местах. Это вызовет конфликты и в результате огромное векторное дерево часов:/..не так плохо, не так хорошо.

У Риака есть еще один "механизм". Он имеет 2-слойное пространство имен ключей, так называемое ведро и ключ. Так, например, для студентов, Если у нас есть клуб A, B и C и studentx, StudentY вы могли бы поддерживать следующее соглашение:

{ Key = {ClubA, StudentX}, Value = true }, 
{ Key = {ClubB, StudentX}, Value = true }, 
{ Key = {ClubA, StudentY}, Value = true }

и для чтения отношения просто перечислите ключи в заданных ведрах. Whats неправильно с этим? Это чертовски медленно. Риаку никогда не нравилось перечислять ведра. Становится все лучше и лучше. кстати. вы не тратите память, потому что этот пример {true} может быть связан с одним полным профилем StudentX или Y (здесь конфликты невозможны).

как вы видите это NoSQL != В NoSQL. Вам нужно посмотреть на конкретную реализацию и проверьте сами.

упомянутые ранее магазины столбцов выглядят хорошо подходящими для отношений.. но все зависит от ваших потребностей A и C и P;) если вам не нужен A, и у вас меньше, чем байты Peta, просто оставьте его, продолжайте MySql или Postgres.

удачи


вы

"user": {
    "userid": "unique value",
    "category": "student",
    "metainfo": "yada yada yada",
    "clubs": ["archery", "kendo"]
}

"comments": {
    "commentid": "unique value",
    "pageid": "unique value",
    "post-time": "ISO Date",
    "userid": "OP id -> THIS IS IMPORTANT"
}

"page": {
    "pageid": "unique value",
    "post-time": "ISO Date",
    "op-id": "user id",
    "tag": ["abc", "zxcv", "qwer"]
}

Ну, в реляционной базе данных нормальная вещь, которую нужно сделать, будет в отношении "один ко многим" - нормализовать данные. Это то же самое, что и в базе данных NoSQL. Просто индексируйте поля, с помощью которых вы будете получать информацию.

например, важные индексы для вас are

  • комментарий.Имя пользователя
  • комментарий.PageID
  • комментарий.PostTime
  • страница.Tag []

Если вы используете NosDB (база данных NoSQL на базе .NET с поддержкой SQL) ваши запросы будут как

 SELECT * FROM Comments WHERE userid = ‘That user’;

 SELECT * FROM Comments WHERE pageid = ‘That user’;

 SELECT * FROM Comments WHERE post-time > DateTime('2016, 1, 1');

 SELECT * FROM Page WHERE tag = 'kendo'

проверьте все поддерживаемые типы запросов из их лист для SQL чит или документации.