дизайн "схемы" для социальной сети - PullRequest
17 голосов
/ 15 мая 2010

Я работаю над проверкой концепции приложения для социальной сети в стиле твиттер с около 500 тысячами пользователей. Я не уверен, как лучше спроектировать «схему»

я должен встраивать подписки пользователя или иметь отдельную коллекцию подписок и использовать ссылки на БД? Если я встраиваюсь, мне все равно придется выполнить запрос, чтобы получить всех подписчиков пользователя. например,

Учитывая следующее пользователя:

{
 "username" : "alan",
 "photo": "123.jpg",
 "subscriptions" : [
    {"username" : "john", "status" : "accepted"},
    {"username" : "paul", "status" : "pending"}
  ]
}

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

db.users.find({'subscriptions.username' : 'alan'});

с точки зрения производительности, это хуже или лучше, чем иметь отдельную коллекцию подписок?

также, при отображении списка подписок / подписчиков у меня в настоящее время возникают проблемы с n + 1, поскольку в документе подписки указано имя пользователя целевого пользователя, но нет других атрибутов, которые мне могут понадобиться, таких как фотография профиля. Есть ли рекомендуемые практики для таких ситуаций?

спасибо Alan

Ответы [ 2 ]

12 голосов
/ 17 мая 2010

Прежде всего, вы должны знать, какие компромиссы вы получите с MongoDB и любой другой базой данных NoSQL (но поймите, что я фанат этого). Если вы пытаетесь полностью нормализовать ваши данные, вы делаете большую ошибку. Даже в реляционных базах данных чем больше становится ваше приложение, тем больше денормализуются ваши данные (см. этот пост * Hot2 Potato). Я видел это снова и снова. Вы не должны сходить с ума и делать огромный беспорядок, но не беспокойтесь о повторении информации в двух местах. Одним из основных моментов (на мой взгляд) NoSQL является то, что ваша схема перемещается в ваш код, а не только в базу данных.

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

Вы можете записать некоторые входные данные в Python или Perl или что угодно, и использовать файл имен для генерации некоторых отношений. Посетите веб-сайт Census , на котором есть список фамилий. Скачайте файл dist.all.last и напишите какую-нибудь программу вроде:

#! /usr/bin/env python
import random as rand

f = open('dist.all.last')
names = []
for line in f:
  names.append(line.split()[0])

rels = {}
for name in names:
  numOfFriends = rand.randint(0, 1000)
  rels[name] = []
  for i in range(numOfFriends):
    newFriend = rand.choice(names)
    if newFriend != name: #cannot be friends with yourself
      rels[name].append(newFriend)

# take relationships (i.e. rels) and write them to MongoDB

Кроме того, как общее примечание, ваши имена полей кажутся довольно длинными. Помните, что имена полей повторяются с каждым документом в этой коллекции, потому что вы не можете полагаться на одно поле, находящееся в любом другом документе. Для экономии места общей стратегией является использование более коротких имен полей, таких как «unam» вместо «username», но это мелочь. Смотрите великий совет в этих двух сообщениях.

EDIT:

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

{
 "username" : "alan",
 "photo": "123.jpg",
 "subscriptions" : [
    {"username" : "john", "status" : "accepted"},
    {"username" : "paul", "status" : "pending"}
  ]
}

Как вы сказали выше, я бы сделал это:

{
 "username" : "alan",
 "photo": "123.jpg",
 "acc_subs" : [ "john" ],
 "pnd_subs" : [ "paul" ]
}

Чтобы у вас мог быть индекс для каждого типа подписки, таким образом, создавая запросы типа "Привет, у многих людей есть ожидающий Пол?" и "Сколько людей подписались на Павла?" супер быстрый в любом случае. Индексирование Mongo по значениям массива - это действительно грандиозная победа.

2 голосов
/ 24 мая 2010

@ Alan B : Я думаю, что вы полностью получаете MongoDB. Я согласен с @ daveslab версией данных, но вы, вероятно, также захотите добавить "последователей".

{
 "username" : "alan",
 "photo": "123.jpg",
 "acc_subs" : [ "john" ],
 "pnd_subs" : [ "paul" ]
 "acc_fol" : [ "mike", "ray" ],
 "pnd_fol" : [ "judy" ]
}

Да, это дублирующая информация. Это зависит от «бизнес-уровня», чтобы гарантировать, что эти данные корректно обновляются в обоих точках. К сожалению, в Mongo нет транзакций, к счастью, у вас есть операция $ addToSet, поэтому вы в полной безопасности.

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