отношения «многие ко многим» для социального приложения: Mongodb или графовые базы данных, такие как Neo4j

Я пытался понять встраивание в Mongodb, но не смог найти достаточно хорошей документации. Связывание не рекомендуется, так как записи не являются атомарными по документам, а также есть два поиска. Кто-нибудь знает, как это решить, или вы бы предложили мне перейти к графическим базам данных, таким как neo4j.

Я пытаюсь создать приложение, для которого потребуются отношения «многие ко многим». Чтобы объяснить, я возьму пример с библиотекой. Он может предлагать книги пользователю на основе книг, которые читают его друзья и соседи (единомышленники).

Есть Пользователи и Книги. Пользователи берут книги и имеют друзей, которые являются другими пользователями

  1. Учитывая пользователя, мне нужны все книги, которые он читает, и количество общих друзей для книги
  2. Учитывая книгу, мне нужны все люди, которые ее читают. Можно указать пользователя А, это вернет пересечение людей, читающих книгу, и друзей пользователя А. Это взаимная дружба.

Пользователи = [

       { 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 или мне следует посмотреть на граф dbs.


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


Ответы (2)


Отказ от ответственности: я работаю в Neo4j

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

Я предлагаю вам просто сделать быстрый всплеск с базой данных графа и посмотреть, как это происходит.

  • Дублирования не будет
  • у вас есть транзакции для атомарных операций
  • следующие ссылки - естественная операция
  • локальные запросы (например, от пользователя или книги) дешевы и быстры
  • вы можете использовать графические алгоритмы, такие как кратчайший путь, чтобы найти интересную информацию о ваших данных
  • рекомендации и подобные операции естественны для графовых баз данных

Некоторые вопросы:

  • Почему вы выбрали MongoDB в первую очередь?
  • Какой язык реализации вы используете?
person Michael Hunger    schedule 15.02.2012
comment
Спасибо за ответ Михаил. Я использую python и выбрал MOngoDB из-за знакомства и возможности совместного использования. Я все еще анализирую базы данных графов, такие как neo4j, и пытаюсь понять, смогу ли я добиться аналогичной производительности и возможности совместного использования. Если мой вариант использования слишком тривиален для базы данных графа, то использование хранилища документов может быть проще, что вы скажете? - person Sai; 15.02.2012
comment
Я слышал, что производительность чтения neo4j плохая и производительность графовых баз данных в целом. Почему бы просто не использовать РСУБД? - person Konrad; 28.02.2018

Ваше базовое предложение схемы, приведенное выше, отлично подойдет для MongoDB с несколькими предложениями:

  1. Используйте целые числа для идентификаторов, а не строки. MongoDB часто хранит целые числа более компактно (они всегда будут 8 байт, тогда как сохраняемый размер строк будет зависеть от длины строки). Вы можете использовать findAndModify для эмуляции генераторов уникальных последовательностей (например, auto_increment в некоторых реляционных базах данных) — см. SequenceField Mongoengine для примера того, как это делается. Вы также можете использовать ObjectIds, которые всегда имеют длину 12 байт, но практически гарантированно будут уникальными без необходимости хранения любую координационную информацию в базе данных.
  2. Вы должны использовать поле _id вместо id, так как это поле всегда присутствует в MongoDB и для него создан уникальный индекс по умолчанию. Это означает, что ваши _id всегда уникальны, а поиск по _id выполняется очень быстро.

Вы правы в том, что использование схемы такого типа потребует нескольких find() и каждый раз будет нести накладные расходы по сети в оба конца. Однако для каждого из запросов, которые вы предложили выше, вам нужно не более 2 запросов в сочетании с некоторым простым кодом приложения:

  1. "Для пользователя мне нужны все книги, которые он читает, и количество общих друзей для этой книги"

    a. Найдите нужного пользователя, а затем
    b. запросить коллекцию книг с помощью db.books.find({_id: {$in: [list, of, books, for, the, user]}}), а затем
    c. Для каждой книги вычислите объединение множества для читателей этой книги и друзей пользователя.
  2. "Если у меня есть книга, мне нужны все, кто ее читает".

    а. Найдите нужную книгу, а затем
    b. Найдите всех пользователей, которые читают эту книгу, снова используя $in например db.users.find({_id: {$in: [list, of, users, reading, book]}})
  3. "Можно указать пользователя А, это вернет пересечение людей, читающих книги, и друзей пользователя А".

    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