Wie kann ich diesen PHP / MySQL News Feed verbessern?
Lassen Sie mich beginnen rechts von der Fledermaus sagen, dass ich weiß, das ist nicht die beste Lösung. Ich weiß, es ist notdürftigem und ein Einbruch in eine Funktion. Aber das ist der Grund, warum ich hier bin!
Diese Frage/Arbeit baut auf einige Diskussion auf Quora mit Andrew Bosworth, der Schöpfer von Facebook ' s news feed.
Baue ich ein news-feed der Arten. Es ist gebaut, allein in PHP
und MySQL
.
Die MySQL
Das relationale Modell für die Einspeisung besteht aus zwei Tabellen. Ein Tisch fungiert als eine Aktivität protokollieren; in der Tat, es ist benannt activity_log
. Die andere Tabelle ist newsfeed
. Diese Tabellen sind fast identisch.
Den schema für die log - ist activity_log(uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)
...und die schema für die feed ist newsfeed(uid INT(11), poster_uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)
.
Jedes mal, wenn ein Benutzer etwas tut, relevant für die news-feed, zum Beispiel die Frage, es wird protokolliert, um die Aktivität log sofort.
Generieren die news-feeds
Dann alle X Minuten (5 Minuten im moment, wird sich ändern, auf 15-30 Minuten später), ich einen cron-job , führt das Skript unten. Dieses Skript durchläuft alle Benutzer in der Datenbank, findet alle Aktivitäten, die für alle Benutzer, Freunde, und schreibt dann diese Aktivitäten auf der news-feed.
In dem moment, das SQL
entnimmt, dass die Aktivität (genannt in ActivityLog::getUsersActivity()
) hat eine LIMIT 100
verhängt Leistung* Gründen. *Nicht, dass ich weiß, wovon ich spreche.
<?php
$user = new User();
$activityLog = new ActivityLog();
$friend = new Friend();
$newsFeed = new NewsFeed();
//Get all the users
$usersArray = $user->getAllUsers();
foreach($usersArray as $userArray) {
$uid = $userArray['uid'];
//Get the user's friends
$friendsJSON = $friend->getFriends($uid);
$friendsArray = json_decode($friendsJSON, true);
//Get the activity of each friend
foreach($friendsArray as $friendArray) {
$array = $activityLog->getUsersActivity($friendArray['fid2']);
//Only write if the user has activity
if(!empty($array)) {
//Add each piece of activity to the news feed
foreach($array as $news) {
$newsFeed->addNews($uid, $friendArray['fid2'], $news['activity'], $news['activity_id'], $news['title'], $news['time']);
}
}
}
}
Anzeige des news-feeds
In den client-code, der beim abrufen des Benutzers news-feed, ich glaube so etwas wie:
$feedArray = $newsFeed->getUsersFeedWithLimitAndOffset($uid, 25, 0);
foreach($feedArray as $feedItem) {
//Use a switch to determine the activity type here, and display based on type
//e.g. User Name asked A Question
//where "A Question" == $feedItem['title'];
}
Verbesserung der news-feed
Nun vergib meinem begrenzten Verständnis der best practices für die Entwicklung einer news-feed, aber ich verstehe den Ansatz, den ich verwende, um eine eingeschränkte version, was heißt fan-out-on-write -, begrenzt in dem Sinne, dass ich bin mit einem cron-job als Zwischenschritt statt zu schreiben, um den Benutzer " news-feeds direkt. Aber dies unterscheidet sich sehr von einem pull-Modell, in dem Sinne, dass der Nutzer den news-feed wird nicht kompiliert, die auf Belastung, sondern auf einer regulären basis.
Dies ist eine große Frage, die sich wohl verdient ein große Menge hin und her, aber ich denke, es kann dienen als ein Prüfstein für viele wichtige Gespräche, die der neue Entwickler wie mich haben müssen. Ich versuche nur, um herauszufinden, was ich falsch mache, wie kann ich verbessern, oder wie darf ich das vielleicht sogar von vorne anfangen und versuchen einen anderen Ansatz.
Eine andere Sache, die nervt mich an diesem Modell ist, dass es funktioniert, basierend auf Neuheit statt Relevanz. Wenn jemand vorschlagen kann, wie dies verbessert werden kann, um Arbeit Relevanz haben, ich wäre ganz Ohr. Ich bin mit dem Gerichteten Kante API, um Empfehlungen zu generieren, aber es scheint, dass so etwas wie ein news-feed, Empfehler wird nicht funktionieren (da nichts war Favoriten bisher!).
InformationsquelleAutor der Frage Josh Smith | 2010-11-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wirklich Coole Frage. Ich bin eigentlich mitten in der Umsetzung so etwas wie dieses selbst. So, ich werde mich, laut zu denken, ein bisschen.
Hier ist der Fehler, die ich in meinem Geist mit Ihrer aktuellen Umsetzung:
Bearbeitung aller Freunde an, die für alle Benutzer, aber Sie werden am Ende der Verarbeitung den gleichen Benutzern viele Male durch die Tatsache, dass die gleichen Gruppen von Menschen haben ähnliche Freunde.
Wenn einer meiner Freunde posten etwas, es wird nicht zeigen, bis auf meinen news-feed für höchstens 5 Minuten. In der Erwägung, dass es sollte sofort angezeigt, richtig?
Lesen wir die gesamte news-feed für einen Benutzer. Nicht wir brauchen nur zu schnappen Sie sich die neuen Aktivitäten seit wir das Letzte mal knirschte die logs?
Diese nicht skalieren, gut.
Den newsfeed sieht aus wie die exakt gleichen Daten wie die Aktivität melden, ich würde mit dem stick eine Aktivitäts-log-Tabelle.
Wenn Sie die Splitter Ihrer Tätigkeit Protokolle über Datenbanken, die es Ihnen erlaubt, zu skalieren, zu erleichtern. Sie können die Splitter Ihre Benutzer, wenn Sie wollen, aber auch, wenn Sie 10 Millionen Nutzer-Datensätze in einer Tabelle, mysql sollte in Ordnung sein zu tun, heißt es. Also, wenn Sie lookup-Benutzer, Sie wissen, die Splitter, um den Zugriff auf die Benutzer, die Protokolle aus. Wenn Sie die Archivierung Ihrer älteren Protokolle jeder so oft, und nur zu halten, einen neuen Satz von Protokollen, die Sie nicht haben, um Splitter als viel. Oder vielleicht sogar bei allen. Können Sie verwalten viele Millionen Datensätze in MySQL, wenn Sie abgestimmt sind auch nur mäßig gut.
Ich würde memcached nutzen für Ihre Benutzer-Tabelle, und möglicherweise sogar den Protokollen selbst. Memcached ermöglicht die cache-Einträge mit bis zu 1 MB in der Größe, und wenn Sie schlau wären für die Organisation Ihrer Schlüssel, die Sie potenziell alle abrufen der aktuellsten Protokolle aus dem cache.
Wäre dies mehr Arbeit so weit wie Architektur betrifft, aber es wird Ihnen erlauben, in Echtzeit arbeiten und skalieren in der Zukunft...vor allem, wenn Sie möchten, dass Benutzer zu starten kommentieren auf jede Buchung. 😉
Hast du diesen Artikel?
http://bret.appspot.com/entry/how-friendfeed-uses-mysql
InformationsquelleAutor der Antwort Dan Spiteri
Würden Sie hinzufügen statistische Verschlagwortung? Ich eine (grob) Umsetzung über explodierende Körper von meinem Dokument, HTML-stripping, Beseitigung häufige Wörter, und zählen der häufigsten Wörter. Ich habe das vor ein paar Jahren, nur so zum Spaß (wie bei jedem solchen Projekt, die Quelle ist Weg), aber es funktionierte für meine temporäre test-blog/forum einrichten. Vielleicht ist es für Ihre news-feed...
InformationsquelleAutor der Antwort Blender
zwischen Sie können mithilfe von user-flags und caching.
Sagen wir, haben ein neues Feld für die Benutzer-als last_activity.
Aktualisieren Sie dieses Feld, wenn Benutzer jede Aktivität.
Halten Sie die fahne, bis was Zeit, die Sie abgerufen haben, die feeds können sagen, es feed_updated_on.
Nun update-Funktion $user->getAllUsers ();, um nur Benutzer zurückgegeben werden, haben last_activity Zeit später, als feed_updated_on.
Dies schließt alle Benutzer, die nicht über jede Aktivität melden :).
Ähnlicher Vorgang für die Nutzer Freunde.
Können Sie auch Zwischenspeichern wie memcache oder Datei-level-caching.
Haben oder einige nosql-DB für die Speicherung der feeds, die als ein Dokument.
InformationsquelleAutor der Antwort Aakash Sharma
Ich versuche zu bauen, ein Facebook-Stil-news-feed auf meine eigenen. Statt der Erstellung einer anderen Tabelle, log-Aktivitäten der Nutzer, rechnete ich den 'Rand' der UNION der Beiträge, Kommentare etc.
Mit ein bisschen Mathematik, berechne ich die 'edge' mit einem exponentiellen Zerfall-Modell, wobei die verstrichene Zeit als unabhängige variable, unter Berücksichtigung der Anzahl der Kommentare, likes, usw jeder Beitrag hat zu formulieren, die lambda-Konstante. Der Rand wird, sinken schnell auf den ersten, aber allmählich verflacht, auf fast 0 nach ein paar Tagen (aber nie 0)
Zeigt das feed, wird jede Kante ist multipliziert mit RAND(). Posts mit höheren Rand wird häufiger angezeigt
Diese Weise mehr beliebte Beiträge haben eine höhere Wahrscheinlichkeit, zu erscheinen in den news-feed, für eine längere Zeit.
InformationsquelleAutor der Antwort Freeman Latif
Anstelle der Ausführung eines cron-Jobs ein post-commit-Skript von einer Art sein. Ich weiß nicht konkret, was die Fähigkeiten von PHP und MySQL sind in diesem Zusammenhang - wenn ich mich Recht erinnere, MySQL InnoDB ermöglicht mehr erweiterte Funktionen als andere Sorten, aber ich erinnere mich nicht, wenn es Dinge wie Trigger in der neuesten version.
sowieso, eine einfache Sorte, die sich nicht auf eine Menge von Datenbank-magic:
wenn user X fügt Inhalt:
1) ein asynchroner Aufruf aus PHP-Seite nach dem Datenbank-commit (async natürlich so, dass der Benutzer die Seite anzeigen, nicht zu warten, bis es!)
Den Aufruf startet eine Instanz des logischen Drehbuch.
2) die Logik-Skript geht nur durch die Liste der Freunde [A,B,C] der Benutzer verpflichtet sich, die neuen Inhalte (im Gegensatz zur Liste mit allen in der DB!) und hängt die Wirkung von user X zu feeds für jeden einzelnen Benutzer.
Konnte man nur speichern diese feeds als straight-up von JSON-Dateien und fügt neue Daten an das Ende jeder. Besser ist natürlich, halten die feeds cache mit einer Sicherung auf Dateisystem-oder BerkeleyDB oder Mongo oder was auch immer Sie mögen.
Dies ist nur eine grundlegende Idee für feeds, basierend auf Neuheit, nicht nach Relevanz. Sie speichern KÖNNTE die Daten sequentiell in dieser Art und Weise und führen Sie dann eine zusätzliche Analyse auf einer pro-Benutzer-basis zu filtern, nach Relevanz, aber dies ist ein schwieriges problem in einer beliebigen Anwendung und wahrscheinlich nicht eine, die leicht behoben, indem eine anonyme web-Benutzer ohne genaue Kenntnis der Anforderungen 😉
jsh
InformationsquelleAutor der Antwort jsh