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

118

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

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

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

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

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

  • Все комментарии пользователя
  • Все активные комментарии
  • Все сообщения с тегом [ключевое слово]
  • Все студенты в клубе или все клубы, в которых состоит студент

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

Xeoncross
источник
Нет единого способа сделать это в базах данных NoSQL, этот вопрос скорее похож на вопрос, как мне отслеживать отношения в программах на C.
stonemetal
3
Вау, тогда я полагаю, что шумиха по поводу замены РСУБД NoSQL невозможна.
Xeoncross
11
Да, NoSQL определенно раздута. Я не говорю, что новые технологии бесполезны в определенных обстоятельствах, но смешно думать, что они заменят РСУБД. См. En.wikipedia.org/wiki/Hype_cycle
Билл Карвин,
1
Разве у вас не было бы просто коллекции «пользователей» и коллекции комментариев. А затем, каждый комментарий просто как свойство «автор», значение которого является обратной ссылкой на идентификатор пользователя?
CodeFinity

Ответы:

187

Все ответы о том, как хранить ассоциации «многие ко многим» «способом NoSQL» сводятся к одному и тому же: хранению данных с избыточностью.

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

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

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

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

Билл Карвин
источник
20
«вам не следует использовать решение NoSQL, если вам нужно использовать данные реляционным способом» - Так как же другим, использующим NoSQL, это сходит с рук? Как вы можете узнать все способы запроса данных при первом проектировании приложения? Например, Fox, мне могут понадобиться недавние комментарии, комментарии пользователя, комментарии по тегу, комментарии для данного сообщения, комментарии, помеченные как спам, активные комментарии, комментарии с наивысшими оценками и т. Д.
Xeoncross
14
Совершенно верно - не существует такой вещи, как «просто работает», как любят утверждать защитники NoSQL. Либо вы выполняете кучу анализа для моделирования реляционных данных, либо заранее проводите анализ наиболее приоритетных запросов, либо проводите кучу дорогостоящих рефакторингов на протяжении всего проекта, когда обнаруживаете, какие части вашего дизайна не получил достаточно анализа заранее.
Билл Карвин
1
Если мы храним данные с избыточностью, как мы должны их обновлять? Например, меняет имя, и он пишет комментарии. Его имя уже изменено в коллекции пользователей, но как изменить все избыточно сохраненные имена в коллекции комментариев?
Мохаммад Кермани
3
@ M98, А, вы нашли слабое место в этой стратегии. Вы должны знать обо всех местах, которые вам нужно обновить, а затем написать код в своем приложении, чтобы обновлять их все при обновлении любого из них. Удачи!
Билл Карвин
2
Та же проблема существует и для денормализованной реляционной базы данных.
Билл Карвин
5

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

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

У Ряка есть еще один «механизм». Он имеет двухуровневое пространство имен ключей, так называемое ведро и ключ. Итак, для примера со студентом, если у нас есть клубы A, B и C и студент StudentX, StudentY, вы можете придерживаться следующего соглашения:

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

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

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

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

удачи

user425720
источник
1
Недавно компания Riak выпустила версию 1.0, в которой добавлена ​​поддержка вторичных индексов при использовании серверной части LevelDB. Очень ценная особенность.
Джон Л.
4
  1. user: userid: comments - разумный подход - считайте его эквивалентом индекса столбца в SQL с дополнительным требованием, согласно которому вы не можете запрашивать неиндексированные столбцы.

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

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

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

Том Кларксон
источник
Итак, в основном все просто нужны списки? Похоже, должен быть более изощренный подход, чем просто отслеживание строк идентификаторов вручную. Во-первых, вы можете зайти так далеко, прежде чем они станут полезными. Опять же, основные дочерние проекты технологии NoSQL (MongoDB, CouchDB, Membase и т. Д.) - это все новые проекты, поэтому, возможно, мне просто нужно дать им больше времени, чтобы придумать лучший способ отслеживания отношений.
Xeoncross
Если вы используете NoSQL (также известные как нереляционные хранилища данных), вам нужно перестать думать в реляционных терминах. Используемый подход будет отличаться для разных платформ, но основная идея управления индексами довольно универсальна. Приведенные вами примеры отношений моделируются в NoSQL двумя разными способами: 1) Хранилище - в отличие от SQL, столбцы могут иметь несколько / комплексных значений, поэтому дочерний объект является просто частью родительского объекта. 2) Поиск - ваши длинные списки на самом деле являются требованием для возможности поиска, что означает индексацию - вы можете использовать простой настраиваемый список или более полную поисковую систему.
Том Кларксон
2

У тебя есть

"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. Просто проиндексируйте поля, по которым вы будете получать информацию.

Например, важные для вас показатели

  • Comment.UserID
  • Comment.PageID
  • Comment.PostTime
  • Page.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 или документации.

Басит Анвер
источник