このPHP/MySQLニュースフィードを改善するにはどうすればよいですか?
質問
これが最善の解決策でないことは承知していると言うことから始めましょう。不器用で、機能をハックするものであることは承知しています。 しかし、だからこそ私はここにいるのです!
この質問/作業は QuoraでのAndrew Bosworthとの議論 とのQuoraでの議論を基にしたものです。
ニュースフィードを作っています
のようなものを作っています。それはもっぱら
PHP
と
MySQL
.
<イグ
MySQL
フィードのリレーショナルモデルは2つのテーブルで構成されています。1つのテーブルはアクティビティログとして機能し、実際、このテーブルの名前は
activity_log
. もうひとつのテーブルは
newsfeed
.
これらのテーブルはほぼ同じです。
は
スキーマ
は
activity_log(uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)
...そして
スキーマは
は
newsfeed(uid INT(11), poster_uid INT(11), activity ENUM, activity_id INT(11), title TEXT, date TIMESTAMP)
.
ユーザーが何かをするときはいつでも をしたとき、例えば質問をしたときなどです。 活動ログに記録されます。 にすぐに記録されます。
ニュースフィードを生成する
次に X分ごとに (と表示します(現時点では5分、後に15~30分に変更予定)。 cronジョブを実行する を実行し、以下のスクリプトを実行します。このスクリプトはデータベース内のすべてのユーザーをループし、そのユーザーのすべての友人のすべてのアクティビティを見つけ、そしてそれらのアクティビティをニュースフィードに書き込みます。
現時点では
SQL
で呼ばれる)アクティビティをカリングする
ActivityLog::getUsersActivity()
) には
LIMIT 100
はパフォーマンス*のために課されたものです。*私が何を言っているのか分かりませんが。
<?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']);
}
}
}
}
ニュースフィードを表示する
クライアントコードでは、ユーザーのニュースフィードを取得するときに、次のようなことをしています。
$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'];
}
ニュースフィードの改善
ニュースフィードを開発するためのベストプラクティスについての私の限られた理解をお許しください。しかし私は、私が使っているアプローチは、いわゆる 書き込み時のファンアウト の限定版であり、ユーザーのニュースフィードに直接書き込むのではなく、中間段階としてcronジョブを実行しているという意味で、限定的であると理解しています。しかしこれは、ユーザーのニュースフィードがロード時にコンパイルされるのではなく、定期的にコンパイルされるという意味で、プルモデルとは非常に異なっています。
これは、おそらく多くの行き違いに値する大きな質問ですが、私のような新しい開発者が持つ必要のある多くの重要な会話の試金石になることができると思います。私は、何が間違っているのか、どのように改善できるのか、あるいは、どのようにゼロから始めて別のアプローチを試すべきかを理解しようとしているところです。
このモデルについて悩ましいもう1つの点は、関連性よりも再帰性に基づいて動作することです。このモデルをどのように改良して関連性を持たせるか、どなたかご提案いただければ幸いです。私はレコメンデーションを生成するためにDirected EdgeのAPIを使用していますが、ニュースフィードのようなものではレコメンダーは機能しないようです(以前は何もお気に入りされていなかったからです!)。
どうすれば解決できますか?
本当にクールな質問ですね。実は私自身、このようなものを実装している最中なんです。だから、少し声を出して考えてみます。
あなたの現在の実装について、私の頭の中にある欠点は以下の通りです。
-
すべてのユーザーの友達を処理していますが、同じグループの人々が同じような友達を持っているという事実のために、同じユーザーを何度も処理することになります。
-
私の友人の 1 人が何かを投稿しても、ニュース フィードに表示されるのはせいぜい 5 分間です。一方、すぐに表示されるはずですよね?
-
私たちはユーザーのニュースフィード全体を読んでいます。前回ログを解析したとき以降の新しいアクティビティを取得する必要があるだけではありませんか?
-
これはそれほどうまくスケールしません。
ニュースフィードはアクティビティログと全く同じデータのように見えますが、私ならその1つのアクティビティログテーブルにこだわります。
アクティビティログをデータベース間でシャードすれば、簡単にスケーリングできるようになります。必要に応じてユーザーをシャードすることもできますが、1 つのテーブルに 1,000 万のユーザー レコードがある場合でも、mysql は問題なく読み取りを行うことができます。ユーザーを調べるときはいつでも、どのシャードからそのユーザーのログにアクセスすればいいかがわかるわけです。古いログを頻繁にアーカイブして、新しいログだけを維持するようにすれば、それほどシャード化する必要はないでしょう。あるいは、まったく必要ないかもしれません。中程度のチューニングであれば、MySQL で何百万ものレコードを管理することができます。
私は、ユーザーテーブルと、おそらくログ自体にさえも、memcachedを活用します。Memcached は、最大 1MB のサイズのキャッシュエントリを許可し、キーを整理するのが賢明であれば、キャッシュから最新のログをすべて取得できる可能性があります。
これはアーキテクチャに関する限り、より多くの作業を必要としますが、リアルタイムでの作業と将来のスケールアウトを可能にします...特に、ユーザーが コメント を開始したい場合は特にそうです)。
この記事を見ましたか?
関連
-
[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] PHPでHTML/XMLをパースして処理する方法とは?
-
[解決済み] PHPのエラーを表示させるにはどうしたらいいですか?
-
[解決済み] MySQLのAUTO_INCREMENTをリセットする方法
-
[解決済み] MySQLの複数行を1つのフィールドに連結することはできますか?
-
[解決済み] MySQLでコマンドラインを使用してユーザーアカウントのリストを取得するにはどうすればよいですか?
-
[解決済み] MySQLのクエリ結果をCSV形式で出力するにはどうすればよいですか?
-
[解決済み】PHPの'foreach'は実際どのように動作するのですか?
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】PHPで空の値からデフォルトオブジェクトを作成する?
-
[解決済み】空の配列要素を削除する
-
[解決済み】「初期通信パケットの読み込み」でMySQLサーバーに接続できなくなり、システムエラーになる。0
-
[解決済み】変な電話番号を生成するフェイカー?
-
[解決済み】stdClassクラスのオブジェクトが文字列に変換されない。
-
[解決済み】Laravel 5.2 Storage::makeDirectory($dir) でディレクトリが作成されない。
-
[解決済み】mysqli_select_db()は、パラメータ1がmysqliであることを期待し、文字列が与えられる。
-
[解決済み】既に開始されているPHPセッション【重複あり
-
[解決済み】Fatal error: mysqli_result 型のオブジェクトは使用できません [終了] 。
-
[解決済み】Wordpressの子テーマのstyle.cssが効かない。