How to recommend the next achievement

Short version:

I have a similar setup for StackOverflow. Users get Achievements. I have many other achievements than SO, say, of the order of 10k, and each user has 100 achievements. Now, how would you recommend (recommend) the following achievement for the user to try?

Long version:

Objects are modeled this way in django (showing only the important parts):

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)

and my algorithm is just to find any other user who has a common achievement with a registered user, and then go through all their achievements and sort by the number of occurrences:

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

    // The final response
    r = {}

    // Get all the achievements the user 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

But it requires FOREVER to start and always returns the entire list that is not needed. The user will need only a few of the best achievements.

, / . :)

+5
2

, , , - , , . , , . , . , , ... , , , . ( + , )

( , , , , ) . , k- . , . , , , , , , ( ) , .

, . =)

+3

, (, otherAliases, count) SQL. , 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

.

SQL, , Achiever Alias, , . .

"B" - , "Achiever" - . , "B" , . alias_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

, , , , .

, , - SQL, , " " - . Achiever . , , 10 , .

, , JOIN , success_id 10 , NULL, " t . , NULL ( ).

+2

All Articles