Як ви відстежуєте відносини запису в NoSQL?


117

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

Скажіть, у мене є користувач, і цей користувач залишає багато коментарів по всьому сайту. Єдиний спосіб я можу придумати, щоб слідкувати за коментарями користувачів, це

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

Однак, беручи другий приклад, ви незабаром потрапите на цегляну стіну, коли будете використовувати її для відстеження інших речей, таких як ключ під назвою "active_comments", який може містити в ньому 30 мільйонів ідентифікаторів, що вимагає TON для запиту на кожній сторінці, щоб дізнатись про останні останні активні коментарі. Це також було б дуже схильне до умов перегонів, оскільки багато сторінок можуть спробувати оновити його одночасно.

Як я можу відстежувати такі відносини, як наступні, у базі даних NoSQL?

  • Усі коментарі користувача
  • Усі активні коментарі
  • Усі повідомлення з тегом [ключове слово]
  • Усі студенти в клубі - або всі клуби, в яких є студент

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


Немає жодного способу зробити це в базах даних NoSQL, це питання є досить рідним питанням, як би я відстежував відносини в програмах на С.
каменеметал

3
Нічого, тоді я здогадуюсь, що скандал щодо заміни RDBMS на NoSQL неможливий.
Xeoncross

11
Так, NoSQL, безумовно, завищений. Я не кажу, що нові технології не є корисними в правильних обставинах, але смішно думати, що вони замінять RDBMS. Дивіться en.wikipedia.org/wiki/Hype_cycle
Білл Карвін

1
Чи не було б у вас просто колекція "користувачів" та колекція коментарів. А потім, кожен коментар як власність "автора", значення якої є посиланням на ідентифікатор користувача?
CodeFinity

Відповіді:


186

Усі відповіді про те, як зберігати багато-багато асоціацій "способом NoSQL" зводяться до одного і того ж: надмірне зберігання даних.

У NoSQL ви не проектуєте свою базу даних на основі зв’язків між сутностями даних. Ви розробляєте свою базу даних на основі запитів, на які будете працювати. Використовуйте ті самі критерії, які ви використовували для денормалізації реляційної бази даних: якщо для даних важливіше мати згуртованість (подумайте про значення у списку, розділеному комами, а не в нормалізованій таблиці), тоді зробіть це так.

Але це неминуче оптимізується для одного типу запиту (наприклад, коментарів будь-якого користувача до даної статті) за рахунок інших типів запитів (коментарів до будь-якої статті даного користувача). Якщо у вашій програмі є необхідність обох типів запитів бути однаково оптимізованими, вам не слід денормалізувати. І також не слід використовувати рішення NoSQL, якщо вам потрібно використовувати дані реляційним шляхом.

Існує ризик денормалізації та надмірності, коли надлишкові набори даних вийдуть із синхронізації один з одним. Це називається аномалією . Коли ви використовуєте нормалізовану реляційну базу даних, RDBMS може запобігти аномалії. У денормалізованій базі даних або в NoSQL ваша відповідальність є написання коду програми для запобігання аномалій.

Можна подумати, що для бази даних NoSQL було б чудово виконати важку роботу з запобігання аномалій для вас. Існує парадигма, яка може це зробити - реляційна парадигма.


20
"вам не слід використовувати рішення NoSQL, якщо вам потрібно використовувати дані реляційним шляхом" - Так як же інші, що працюють з NoSQL, відходять від цього? Як ви, можливо, можете знати всі способи запиту даних під час першого проектування програми? Наприклад, Fox, я можу побажати останніх коментарів, коментарів користувача, коментарів до тегів, коментарів до даної публікації, коментарів, позначених як спам, активних коментарів, коментарів з найвищим рейтингом тощо
Xeoncross

14
Саме так - не існує такого поняття, як "воно просто працює", як люблять заявляти прихильники NoSQL. Або ви робите купу аналізу на передній план для реляційного моделювання даних, або ви робите купу аналізу наперед для ваших першочергових запитів, або ви робите купу дорогого рефакторингу впродовж проекту, коли ви дізнаєтесь, які частини вашого дизайну не отримали достатнього аналізу наперед.
Білл Карвін

1
Якщо ми зберігаємо дані надлишково, то як слід оновлювати речі? Наприклад, змінює своє ім’я, і він написав кілька коментарів. Його ім’я вже змінено в колекції користувачів, але як змінити всі надмірно збережені імена в колекції коментарів?
Мохаммед Кермані

3
@ M98, А, ти знайшов слабкість у цій стратегії. Ви повинні знати про всі місця, які потрібно оновити, а потім написати код у своїй програмі, щоб оновити їх під час оновлення будь-якого. Удачі!
Білл Карвін

2
Ця ж проблема існує і для денормалізованої реляційної бази даних.
Білл Карвін

5

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

З іншого боку, Riak має інструмент для побудови відносин. Це посилання. Ви можете ввести адресу пов'язаного документа (тут коментар) до документа «root» (тут документ користувача). Це одна хитрість. Якщо він поширюється, він може бути змінений за один раз у багатьох місцях. Це спричинить конфлікти і, як результат, величезне векторне дерево годинника: / ..не так погано, не так добре.

Riak також має ще один "механізм". У ньому є двошаровий простір імен ключів, так зване відро і ключ. Отже, для прикладу студентів: Якщо у нас є клуби A, B і C та StudentXX, StudentY, ви можете дотримуватися наступних умов:

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

і читати співвідношення лише перелічити ключі в заданих відрах. Що з цим погано? Чорт повільно. Перерахування відра ніколи не було пріоритетним для riak. Це стає все краще і краще. btw. ви не витрачаєте пам’ять, оскільки цей приклад {true}можна пов’язати з єдиним повним профілем StudentX або Y (тут конфлікти неможливі).

Як ви бачите, це NoSQL! = NoSQL. Потрібно переглянути конкретну реалізацію та перевірити її на собі.

Згадані раніше магазини Column виглядають добре підходять для відносин .. але все залежить від ваших потреб A і C і P;) Якщо вам не потрібен A, а у вас менше байтів Peta, просто залиште його, продовжуйте MySql або Postgres.

Щасти


1
Нещодавно Riak випустив v1.0, який додає підтримку вторинних індексів при використанні сервера LevelDB. Дуже цінна особливість.
Джон Л.

4
  1. user: userid: comments - це розумний підхід - подумайте про це як еквівалент індексу стовпців у SQL з додатковою вимогою, яку ви не можете запитувати в недекларованих стовпцях.

  2. Тут потрібно подумати про свої вимоги. Список з 30 мільйонами предметів не є необґрунтованим, тому що він повільний, а тому що недоцільно ніколи щось робити з ним. Якщо ваша реальна вимога полягає у відображенні деяких останніх коментарів, вам краще зберігати дуже короткий список, який оновлюється щоразу, коли коментар додається - пам’ятайте, що NoSQL не вимагає нормалізації. Умови перегонів - це проблема зі списками в базовому сховищі ключових значень, але, як правило, або ваша платформа підтримує списки належним чином, ви можете робити щось із блокуваннями, або вас насправді не цікавлять невдалі оновлення.

  3. Те саме, що і для коментарів користувачів - створіть ключове слово: індекси

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


Отже, в основному все просто потребує списків? Здається, має бути більш досконалий підхід, ніж просто відстеження рядків ідентифікаторів вручну. Для одного, ви можете зайти так далеко, перш ніж вони дістаються до великих, щоб стати в нагоді. Знову ж таки, основні проекти дочірних технологій NoSQL (MongoDB, CouchDB, Membase тощо) - це все нові проекти, тому, можливо, мені просто потрібно дати більше часу, щоб придумати кращий спосіб відстеження відносин.
Xeoncross

Якщо ви використовуєте NoSQL (нереляційні сховища даних AKA), вам потрібно припинити думати у реляційних термінах. Використовуваний підхід буде відрізнятися між платформами, але основна ідея, що вам потрібно керувати індексами, є досить універсальною. Наведені вами приклади відносин моделюються двома способами в 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. Просто індексуйте поля, з якими ви будете отримувати інформацію.

Наприклад, важливі для вас індекси

  • Коментар.UserID
  • Коментар
  • 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 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.