質問

ショートバージョン:

私はStackOverflowのと同様のセットアップを持っています。ユーザーが実績を取得します。私はSOよりも多くの実績を持つ、10Kのために言うことができますし、各ユーザーは、成果の100Sにあります。さて、どのように(推薦する)のためにしようとするユーザーのために、次の成果を勧めますか?

ロングバージョンます:

オブジェクトはジャンゴで、このようにモデル化される(唯一の重要な部品を示す):

class User(models.Model):
    alias = models.ForeignKey(Alias)

class Alias(models.Model):
    achievements = models.ManyToManyField('Achievement', through='Achiever')

class Achievement(models.Model):
    points = models.IntegerField()

class Achiever(models.Model):
    achievement = models.ForeignKey(Achievement)
    alias = models.ForeignKey(Alias)
    count = models.IntegerField(default=1)

と私のアルゴリズムは、ちょうどすべての彼らの功績を通過し、ソート出現回数によって、ユーザのログインと共有実績を持っている他のすべてのユーザーを見つけ、することです。

def recommended(request) :
    user = request.user.get_profile()

    // The final response
    r = {}

    // Get all the achievements the user's aliases have received 
    // in a set so they aren't double counted
    achievements = set()
    for alias in user.alias_set.select_related('achievements').all() :
        achievements.update(alias.achievements.all())

    // Find all other aliases that have gotten at least one of the same
    // same achievements as the user
    otherAliases = set()
    for ach in achievements :
        otherAliases.update(ach.alias_set.all())

    // Find other achievements the other users have gotten in addition to
    // the shared ones.
    // And count the number of times each achievement appears
    for otherAlias in otherAliases :
        for otherAch in otherAlias.achievements.all() :
            r[otherAch] = r.get(otherAch, 0) + 1

    // Remove all the achievements that the user has already gotten
    for ach in achievements :
        r.pop(ach)

    // Sort by number of times the achievements have been received
    r = sorted(r.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)

    // Put in the template for showing on the screen
    template_values = {}
    template_values['achievements'] = r

しかし、それは実行にFOREVERかかり、常に不要です全リストを返します。ユーザーが後にのみ行くことを上位のいくつかの成果が必要になります。

だから、私は他のアルゴリズムおよび/またはコードの改善に関する提言を歓迎しますよ。私は推薦アルゴリズムを考え出すためにあなたに私のシステムで成果をあげる:)

役に立ちましたか?

解決

あなたはどの成果がために行くことをお勧めすることができます一つの方法は、既にこれらの実績を持っているどのように多くのユーザーの参照とそれらの人気のあるものをお勧めすることです。彼らはそれらを達成したときは、リストを下に移動して、わずかに少ない人気のあるものをお勧めします。しかし、これは誰もが人気の成果のために行きたいという素朴な前提を持っています。これはよく...慰めが、これは多くのリソースを占有していないということで、非常に高速に実行する可能性があり、人気の業績はさらに人気とあまり人気のあるものになる可能性があります。

(ただ、実績+それが達成だ回数のリストを保持)

(ユーザーは、彼がすでに持っていたものの成果に基づいて後に行く可能性がある成果を推測しようとした)別の方法は、いくつかの機械学習アルゴリズムを使用することです。私はここで非常によく実行されますの k最近傍アルゴリズムと思います。しきい値と、このしきい値を超えているだけで、出力のすべてを選択します。トップを格納し、一度たびに、ユーザーが新しい実績を作った、これはより速くあなたがすでに持っているものよりも実行する場合さて、私は知らないが、あなただけのリコメンデーション・エンジンを実行する必要があり5を(さんが言わせて)、そしてちょうどそれを出力バックの推薦が必要とされるたびに、ユーザーにます。

私はこのことができます願っています。 =)

他のヒント

私はあなたが1つのSQLステートメントとして最初の3つのステップ(成果、otherAliases、カウント)を行うことを示唆しています。それが今であるとして、あなたは、クエリの多くを発行し、DBに委譲すべき課題であるPythonで数千行をまとめています。例えばコード

for otherAlias in otherAliases : #For every single other user
    for otherAch in otherAlias.achievements.all() : #execute a query
        r[otherAch] = r.get(otherAch, 0) + 1

巨大なクエリの数千人をいます。

その代わりに、エイリアスIDが異なっていると達成IDが同じであることに基づいて、自身に達成者に参加することによってこれを行うためにSQLを使用することができます。その後、達成IDでグループカウントを実行します。

以下のクエリでは、テーブル「B」は、他の利用者の成果であり、「達成者は、」私たちの成果です。他のユーザーが成果を共有している場合、彼らは、彼らが共有し、各達成のための「B」で一度表示されます。私たちは、その後、グループalias_idによるものと、アウトテーブルを数え、彼らはあなたが素敵なIDを取得登場した回数をカウントします。

非常に非常にラフなコード(ここでは利用できていないSQL)

SELECT B.Alias_id, COUNT(B.achievement_id) 
  FROM Achiever, Achiever as B 
  WHERE Achiever.achievement_id == B.achievement_id 
     AND Achiever.Alias_id == <insert current user alias here>;
  GROUP BY B.Alias_id
それは私がそれをすると思うように動作している場合、

、あなたは彼らが現在のユーザーと共有する成果の数と一緒に、他のユーザのエイリアスのテーブルを取得します。

ユーザーそれを呼び出す -

あなたは次のことは、上記の「選択インナー」として1つを使用するSQL文です。あなたは、現在のユーザーのためのあなたの成果テーブルとあなたの達成者のテーブルであることを参加します。あなたは、現在のユーザーに類似している上位10人のユーザが、すべてを無視する場合があります。

私は今良いクエリを記述するための時間を持っていますが、ノミネート10人のユーザーと現在のユーザーの間でachievement_idに参加し、あなたのDBのための結合文を見ていない - それはdoesnの場合は、NULLにそのIDを設定しますtが存在します。それがNULL(未達の成果を)上げ行のみにフィルタ。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top