релации много към много за социално приложение: Mongodb или графични бази данни като Neo4j

Опитах се да разбера вграждането в Mongodb, но не можах да намеря достатъчно добра документация. Свързването не се препоръчва, тъй като записите не са атомарни в документи и също така има две справки. Някой знае ли как да реши това или бихте ми предложили да отида на graph dbs като neo4j.

Опитвам се да създам приложение, което ще се нуждае от връзки много към много. За да обясня, ще взема пример с библиотека. Той може да предлага книги на потребителя въз основа на книги, които неговите приятели четат и съседи (подобно мислещи) потребители, които четат.

Има потребители и книги. Потребителите заемат книги и имат приятели, които са други потребители

  1. Имайки предвид даден потребител, имам нужда от всички книги, които чете, и броя на общите му приятели за книгата
  2. Като имам книга, имам нужда от всички хора, които я четат. Може да се даде потребител A, това ще върне пресечната точка на хора, които четат книга, и приятели на потребител A. Това е взаимно приятелство

Потребители = [

       { name: 'xyz', 'id':'000000', friend_ids:['949583','958694']}

       { name: 'abc', 'id':'000001', friend_ids:['949582','111111']}

      ]

Книги = [

      {'book':'da vinci code', 'author': 'dan brown', 'readers'=['949583', '000000']}

      {'book':'iCon', 'author': 'Young', 'readers'=['000000', '000001']}

      ]

Както се вижда по-горе, обикновено имам нужда от два документа, ако взема mongo DB, тъй като мога да направя двупосочно търсене. Дублирането (вграждането) на документ в друг може да доведе до много дублиране (тези схеми могат да съхраняват много повече информация от показаната).

Правилно ли моделирам данните си? Може ли това да се направи ефективно в mongodb или трябва да погледна graph dbs.


person Sai    schedule 14.02.2012    source източник


Отговори (2)


Отказ от отговорност: работя за Neo4j

От вашата схема, изисквания и тип данни изглежда, че приложението ви е по-скоро в сладко място за бази данни с графики.

Бих ви предложил просто да направите бърз скок с база данни с графики и да видите как върви.

  • Няма да има дублиране
  • имате транзакции за атомарни операции
  • Следването на връзки е естествената операция
  • местните заявки (напр. от потребител или книга) са евтини и бързи
  • можете да използвате графични алгоритми като най-краткия път, за да намерите интересна информация за вашите данни
  • препоръки и подобни операции са естествени за графични бази данни

Някой въпроси:

  • Защо избрахте MongoDB на първо място?
  • Какъв език за изпълнение използвате?
person Michael Hunger    schedule 15.02.2012
comment
Благодаря за отговора Майкъл. Използвам python и избрах MOngoDB заради познаването и функцията за споделяне. Все още анализирам graph dbs като neo4j и се опитвам да видя дали мога да получа подобна производителност и способност за споделяне. Ако моят случай на използване е твърде тривиален за graph db, тогава използването на хранилище на документи може да е по-лесно, какво ще кажете? - person Sai; 15.02.2012
comment
Чух, че производителността при четене на neo4j е лоша и производителността на графичните бази данни като цяло. Защо просто не използвате RDBMS? - person Konrad; 28.02.2018

Вашето основно предложение за схема по-горе ще работи добре за MongoDB, с няколко предложения:

  1. Използвайте цели числа за идентификатори, а не низове. Целите числа често ще се съхраняват по-компактно от MongoDB (те винаги ще бъдат 8 байта, докато съхраненият размер на низовете ще зависи от дължината на низа). Можете да използвате findAndModify, за да емулирате уникални генератори на последователности (като auto_increment в някои релационни бази данни) -- вижте SequenceField на Mongoengine за пример как се прави това. Можете също така да използвате ObjectIds, които винаги са 12 байта, но са практически гарантирани, че са уникални, без да се налага да съхранявате всяка координационна информация в базата данни.
  2. Трябва да използвате полето _id вместо id, тъй като това поле винаги присъства в MongoDB и има уникален индекс по подразбиране, създаден върху него. Това означава, че вашите _ids винаги са уникални и търсенето по _id е много бързо.

Вие сте прав, че използването на този вид схема ще изисква множество find()s и ще налага всеки път режийни разходи за двупосочна мрежа. Въпреки това, за всяка от заявките, които предложихте по-горе, не са ви необходими повече от 2 търсения, комбинирани с някакъв прост код на приложение:

  1. „При даден потребител ми трябват всички книги, които чете, и брой общи приятели за книгата“

    a. Потърсете въпросния потребител, след което
    b. потърсете колекцията от книги, като използвате db.books.find({_id: {$in: [list, of, books, for, the, user]}}), след това
    c. За всяка книга изчислете обединение на множество за читателите на тази книга плюс приятелите на потребителя
  2. „При дадена книга имам нужда от всички хора, които я четат.“

    a. Потърсете въпросната книга, след което
    b. Потърсете всички потребители, които четат тази книга, като отново използвате $in като db.users.find({_id: {$in: [list, of, users, reading, book]}})
  3. „Може да бъде даден потребител A, това ще върне пресечната точка на хора, които четат книга, и приятели на потребител A.“

    a. Потърсете въпросния потребител, след което
    b. Потърсете въпросната книга, след което
    c. Изчислете набора от приятели на потребителя и читатели на книгата

Трябва да отбележа, че $in може да бъде бавен, ако имате много дълги списъци, тъй като на практика е еквивалентен на извършване на N брой търсения за списък от N елемента. Сървърът обаче прави това вместо вас, така че изисква само едно двупосочно пътуване в мрежата, а не N.

Като алтернатива на използването на $in за някои от тези заявки, можете да създадете индекс върху полетата на масива и да заявите колекцията за документи с конкретна стойност в масива. Например, за заявка №1 по-горе, можете да направите:

// create an index on the array field "readers"
db.books.ensureIndex({readers: 1})

// now find all books for user whose id is 1234
db.books.find({readers: 1234})

Това се нарича многоключов индекс и може да работи по-добре от $in в някои случаи. Вашият точен опит ще варира в зависимост от броя на документите и размера на списъците.

person dcrosta    schedule 15.02.2012