2010-05-15 3 views
17

Ich arbeite an einer Proof-of-Concept-App für ein soziales Netzwerk Twitter-Stil mit etwa 500k Benutzer. Ich bin mir nicht sicher, wie ich das 'Schema' am besten gestalten soll.'Schema' Design für ein soziales Netzwerk

Sollte ich die Abonnements eines Benutzers einbetten oder eine separate 'subscriptions'-Sammlung haben und db-Referenzen verwenden? Wenn ich einbette, muss ich noch eine Abfrage durchführen, um alle Follower eines Benutzers zu erhalten. z.B.

Angesichts der folgenden Benutzer:

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

alle Alans Abonnenten zu finden, würde ich so etwas zu laufen haben:

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

von einem Performance-Sicht ist, dass jede schlechter oder besser als eine separate Abo-Sammlung?

Auch, wenn ich eine Liste von Abonnenten/Abonnenten anzeigen, habe ich derzeit Probleme mit n + 1, weil das Abonnement-Dokument mir den Benutzernamen des Zielbenutzers, aber nicht andere Attribute wie das Profilfoto benötigt. Gibt es empfohlene Praktiken für solche Situationen?

dank Alan

Antwort

11

Zunächst einmal sollten Sie die Vor- und Nachteile kennen Sie mit MongoDB und jeder anderen NoSQL-Datenbank erhalten werden (aber klar, dass ich ein Fan von ihm bin). Wenn Sie versuchen, Ihre Daten vollständig zu normalisieren, machen Sie einen großen Fehler. Selbst in relationalen Datenbanken, je größer Ihre App wird, desto mehr werden Ihre Daten denormalisiert (siehe this post von Hot Potato). Ich habe das immer wieder gesehen. Sie sollten nicht verrückt werden und ein riesiges Durcheinander machen, aber machen Sie sich keine Sorgen darüber, Informationen an zwei Stellen zu wiederholen. Einer der wichtigsten Punkte (meiner Meinung nach) von NoSQL ist, dass sich Ihr Schema in Ihren Code und nicht nur in die Datenbank einfügt.

Jetzt, um Ihre Frage zu beantworten, denke ich, Ihre erste Strategie ist, was ich tun würde. MongoDB kann Indizes auf Elemente platzieren, die Arrays sind, so dass die Dinge viel schneller werden, wenn Sie suchen, wie viele Freundschaften ein Benutzer hat. Aber in Wirklichkeit ist der einzige Weg, um wirklich sicher zu sein, ein Testprogramm auszuführen, das eine Datenbank voller Namen und Beziehungen generiert.

Sie können einige Eingabe in Python oder Perl oder was auch immer Sie möchten, Skript erstellen und eine Datei mit Namen verwenden, um einige Beziehungen zu generieren. Überprüfen Sie die Census website, die eine Liste der Nachnamen hat. Laden Sie die Datei dist.all.last und schreibt einige Programme wie:

#! /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 

Auch als allgemeine Anmerkung, Ihre Feldnamen Art lang erscheinen. Denken Sie daran, dass die Feldnamen mit jedes Dokument in dieser Sammlung wiederholt werden, da Sie sich nicht darauf verlassen können, dass sich ein Feld in einem anderen Dokument befindet. Um Platz zu sparen, ist eine allgemeine Strategie, kürzere Feldnamen wie "unam" anstelle von "username" zu verwenden, aber das ist eine kleine Sache. Sehen Sie den großen Rat in thesetwo Beiträge.

EDIT:

Eigentlich Ihr Problem ein wenig mehr in grübeln, würde ich noch einen Vorschlag machen: bricht die Abonnement-Typen in verschiedene Bereiche bis zu den Indizes effizienter zu machen.Zum Beispiel statt:

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

Wie Sie oben gesagt, würde ich dies tun:

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

Damit Sie einen Index für jede Art des Abonnements haben könnte, so dass Anfragen wie „Hoy machen viele Leute haben Paul als schwebend? " und "Wie viele Leute abonnieren Paul?" super schnell oder so. Mongo's Indexierung über Array-Werte ist wirklich ein epischer Gewinn.

+2

netter Beitrag, +1, aber ich bin nicht einverstanden, Namen kurz zu machen. Machen Sie sie so lange wie nötig, um einem anderen Entwickler nichts erklären zu müssen. Dann Profil/optimieren wie benötigt. Wenn Namen beim Skalieren ein erhebliches Größenproblem darstellen, dann refaktorieren. – Lee

2

@Alan B: Ich denke, dass Sie MongoDB total bekommen. Ich stimme zu @daveslab Version der Daten, aber Sie werden wahrscheinlich auch "Anhänger" hinzufügen möchten.

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

Ja, es sind doppelte Informationen. Es liegt an der "Business-Schicht", sicherzustellen, dass diese Daten in beiden Bereichen korrekt aktualisiert werden. Leider gibt es keine Transaktionen in Mongo, glücklicherweise haben Sie die $ addToSet-Operation, so dass Sie ziemlich sicher sind.

Verwandte Themen