3

人々が協調フィルタリングやレコメンデーション エンジンなどにどのようにアプローチしているかを知りたいと思っています。これは、何よりもスクリプトのパフォーマンスの観点からです。私は、Programming Collective Intelligence を読んでいると述べました。これは非常に興味深いものですが、物事のアルゴリズム面により焦点を当てる傾向があります。

現在、ユーザーは 2,000 人しかいませんが、現在のシステムは完全に将来性がなく、サーバーにすでに非常に負担がかかっていることが証明されています。システム全体は、ユーザーへの投稿の推奨に基づいています。私のアプリケーションは PHP/MySQL ですが、協調フィルタリングに MongoDB を使用しています。大規模な Amazon EC2 インスタンスを使用しています。私のセットアップは、実際には 2 ステップのプロセスです。最初にアイテム間の類似性を計算し、次にこの情報を使用してレコメンデーションを作成します。仕組みは次のとおりです。

まず、私のシステムはユーザーの投稿間の類似性を計算します。スクリプトは、各ペアの類似度スコアを返すアルゴリズムを実行します。アルゴリズムは、一般的なタグ、一般的なコメント投稿者、一般的ないいね! などの情報を調べ、類似度スコアを返すことができます。プロセスは次のようになります。

  • 投稿が追加されたり、タグが追加されたり、コメントが付けられたり、いいね! が付けられたりするたびに、それをキューに追加します。
  • 私はこのキューを cron 経由で (1 日 1 回) 処理し、各投稿の関連情報 (コメント投稿者といいね! の user_id、tag_id など) を見つけます。この情報を次のような構造で MongoDB に保存します: {"post_id":1,"tag_ids":[12,44,67],"commenter_user_ids":[6,18,22],"liker_user_ids":[87, 6]}。これにより、MongoDB コレクションを最終的に構築することができ、類似性を計算しようとするときに、すべての関連情報に簡単かつ迅速にアクセスできます。
  • 次に、別の cron スクリプトを実行します (これも 1 日に 1 回ですが、前のスクリプトの後)、再びキューを通過します。今回は、キュー内の各投稿について、MongoDB コレクションからエントリを取得し、それを他のすべてのエントリと比較します。2 つのエントリに一致する情報がある場合は、類似性に関して +​​1 を付けます。最後に、投稿の各ペアの総合スコアを取得します。次の構造を持つ別の MongoDB コレクションにスコアを保存します: {"post_id":1,"similar":{"23":2,"2":5,"7":2}} ('similar' はpost_id をキー、類似度スコアを値とする key=>value 配列 0 の場合はスコアを保存しません。

5kの投稿があります。したがって、上記のすべてはサーバー上で非常に困難です。大量の読み取りと書き込みを実行する必要があります。さて、これは問題の半分にすぎません。次に、この情報を使用して、特定のユーザーにとってどの投稿が興味深いかを判断します。そのため、1 時間に 1 回、サイトのユーザーごとに 1 つの推奨投稿を計算するスクリプトを実行する cron スクリプトを実行します。プロセスは次のようになります。

  • スクリプトは最初に、ユーザーが取得するレコメンデーションのタイプを決定します。1. あなたの投稿の 1 つに似た投稿、または 2. あなたがやり取りした投稿に似た投稿。
  • 1 の場合、スクリプトは MySQL からユーザーの post_ids を取得し、それらを使用して MongoDB から同様の投稿を取得します。スクリプトは、最も類似しており、まだユーザーに推奨されていない投稿を取得します。
  • 2 の場合、スクリプトは、ユーザーが MySQL からコメントまたはいいね! を付けたすべての投稿を取得し、それらの ID を使用して上記の 1 と同じことを行います。

残念ながら、1 時間ごとの推奨スクリプトはリソースを大量に消費するようになり、完了するまでに時間がかかります... 現在 10 ~ 15 分です。ある時点で、時間ごとの推奨事項を提供できなくなるのではないかと心配しています。

誰かが私がこれにもっとうまくアプローチできると感じているかどうか疑問に思っていますか?

4

2 に答える 2

2

5,000 件の投稿で、25,000,000 の関係があり、O(n^2) が増加します。

最初の問題は、バッチを実行するたびに非常に多くの関係を調べないようにする方法です。タグまたはキーワードを使用すると、コンテンツの一致に役立ちます。また、日付範囲を使用して、一般的な「いいね」を制限できます。それを超えて....関係を確立するための方法論についてもっと知りたい.

別の考慮事項は、関係を確立するときです。新しい投稿を既存のデータと比較するためにバッチが実行されるまで待つのはなぜですか? 確かに、これを非同期で処理して、リクエストが迅速に処理されるようにすることは理にかなっていますが、(プラットフォームによって課される制限を除いて) 関係を確立する前に、バッチが開始されるまで待つ必要はありません。非同期メッセージ キューを使用します。

実際、メッセージの処理にかかる時間によっては、アイテムの作成時ではなく取得時に、キャッシュされた関係データを再生成する場合さえあるかもしれません。

データとの関係を測定するためのプラットフォームを作成する場合 (手がかりは名前にあります)、結合が簡単で、ロジックの多くをデータベース層に実装できるリレーショナル データベースに傾倒することは間違いありません。

システムがデータを相互参照するのにかかる時間を短縮することは確かに可能です。これは、まさに map-reduce が対処しようとしている種類の問題です。しかし、この利点は主に、多くのマシンで並列にアルゴリズムを実行することから得られます。1 日の終わりには、同じくらい多くのクロック ティックが必要になります。

于 2012-01-16T13:53:46.540 に答える
1

私はこれを行う方法を計画し始めています。まず、データベース テクノロジを削除するか、トリプルストアまたはグラフ テクノロジで補完することをお勧めします。これにより、類似のいいねやトピックを分析する際のパフォーマンスが向上するはずです。

次にはい、サブセットを取得します。ユーザーが持っているいくつかの関心を取り、同様の関心を持つユーザーの小さなプールを取得します。

次に、ある種の意味のある順序で好きなもののインデックスを作成し、反転を数えます (分割と征服 - これはマージ ソートと非常によく似ており、分割反転をカウントするために途中でソートする必要があります)。

それが役立つことを願っています-すべてを他のすべてと比較したくないか、間違いなくn2です。同様の好みを持つ人々のセットを取り、それを使用すると、それを定数と線形の間のどこかに置き換えることができるはずです。

たとえば、グラフの観点から、彼らが最近気に入ったものを取り上げ、イン エッジを見て、それらをトレースしてそれらのユーザーを分析します。おそらく、最近気に入ったいくつかの記事でこれを行い、そこから共通のユーザーのセットを見つけて、それを協調フィルタリングに使用して、ユーザーが楽しむ可能性が高い記事を見つけます。次に、実行可能な問題のサイズになります-特にインデックスの成長がないグラフでは(ただし、記事をトラバースするエッジが増える可能性がありますが、使用可能なデータを見つけるための変更が増えるだけです)

記事自体にキーを設定して、ある記事が誰かに気に入られた場合、他のユーザー (つまり、Amazon の「これを購入したユーザーも購入した」) に基づいてその人が好む可能性がある記事を表示できるようにすることをお勧めします。

いくつかのアイデアが得られることを願っています。グラフ分析には、統計や派生の faunus のように役立つフレームワークがいくつかあります。

于 2013-02-04T18:10:54.033 に答える