2010-05-15 2 views
17

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

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

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

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

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

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

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

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

благодаря Алан

ответ

11

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

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

Вы можете записывать некоторые данные на Python или Perl или как угодно, и использовать файл имен для создания некоторых отношений. Проверьте Census website, у которого есть список фамилий. Скачать файл 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», но это небольшая вещь. См. Отличный совет в thesetwo сообщений.

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" ] 
} 

Так что вы могли бы иметь индекс для каждого типа подписки, таким образом, делая запросы, как «Hoy много у людей есть Павел в ожидании? " и «Сколько людей подписывается на Пола?» супер быстрый в любом случае. Индексирование Монго по значениям массива действительно является эпической победой.

+2

хороший пост, +1, но я не согласен с тем, чтобы сделать имена короткими. Сделайте их настолько необходимыми, чтобы не нужно было ничего объяснять другому разработчику. Затем профиль/оптимизируйте по мере необходимости. Если имена являются проблемой значительного размера при масштабировании, то рефакторинг. – Lee

2

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

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

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