def rate_contest(contest): from judge.models import Rating, Profile cursor = connection.cursor() cursor.execute(''' SELECT judge_rating.user_id, judge_rating.rating, judge_rating.volatility, r.times FROM judge_rating INNER JOIN judge_contest ON (judge_contest.id = judge_rating.contest_id) INNER JOIN ( SELECT judge_rating.user_id AS id, MAX(judge_contest.end_time) AS last_time, COUNT(judge_rating.user_id) AS times FROM judge_contestparticipation INNER JOIN judge_rating ON (judge_rating.user_id = judge_contestparticipation.user_id) INNER JOIN judge_contest ON (judge_contest.id = judge_rating.contest_id) WHERE judge_contestparticipation.contest_id = %s AND judge_contest.end_time < %s AND judge_contestparticipation.user_id NOT IN ( SELECT profile_id FROM judge_contest_rate_exclude WHERE contest_id = %s ) AND judge_contestparticipation.virtual = 0 GROUP BY judge_rating.user_id ORDER BY judge_contestparticipation.score DESC, judge_contestparticipation.cumtime ASC, judge_contestparticipation.tiebreaker ASC ) AS r ON (judge_rating.user_id = r.id AND judge_contest.end_time = r.last_time) ''', (contest.id, contest.end_time, contest.id)) data = {user: (rating, volatility, times) for user, rating, volatility, times in cursor.fetchall()} cursor.close() users = contest.users.order_by('is_disqualified', '-score', 'cumtime', 'tiebreaker') \ .annotate(submissions=Count('submission')).exclude(user_id__in=contest.rate_exclude.all()) \ .filter(virtual=0, user__is_unlisted=False).values_list('id', 'user_id', 'score', 'cumtime') if not contest.rate_all: users = users.filter(submissions__gt=0) if contest.rating_floor is not None: users = users.exclude(user__rating__lt=contest.rating_floor) if contest.rating_ceiling is not None: users = users.exclude(user__rating__gt=contest.rating_ceiling) users = list(tie_ranker(users, key=itemgetter(2, 3))) participation_ids = [user[1][0] for user in users] user_ids = [user[1][1] for user in users] ranking = list(map(itemgetter(0), users)) old_data = [data.get(user, (1200, 535, 0)) for user in user_ids] old_rating = list(map(itemgetter(0), old_data)) old_volatility = list(map(itemgetter(1), old_data)) times_ranked = list(map(itemgetter(2), old_data)) rating, volatility = recalculate_ratings(old_rating, old_volatility, ranking, times_ranked) now = timezone.now() ratings = [Rating(user_id=id, contest=contest, rating=r, volatility=v, last_rated=now, participation_id=p, rank=z) for id, p, r, v, z in zip(user_ids, participation_ids, rating, volatility, ranking)] cursor = connection.cursor() cursor.execute('CREATE TEMPORARY TABLE _profile_rating_update(id integer, rating integer)') cursor.executemany('INSERT INTO _profile_rating_update VALUES (%s, %s)', list(zip(user_ids, rating))) with transaction.atomic(): Rating.objects.filter(contest=contest).delete() Rating.objects.bulk_create(ratings) cursor.execute(''' UPDATE `%s` p INNER JOIN `_profile_rating_update` tmp ON (p.id = tmp.id) SET p.rating = tmp.rating ''' % Profile._meta.db_table) cursor.execute('DROP TABLE _profile_rating_update') cursor.close() return old_rating, old_volatility, ranking, times_ranked, rating, volatility
def rate_contest(contest): from judge.models import Rating, Profile rating_subquery = Rating.objects.filter(user=OuterRef('user')) rating_sorted = rating_subquery.order_by('-contest__end_time') users = contest.users.order_by('is_disqualified', '-score', 'cumtime', 'tiebreaker') \ .annotate(submissions=Count('submission'), last_rating=Coalesce(Subquery(rating_sorted.values('rating')[:1]), RATING_INIT), last_mean=Coalesce(Subquery(rating_sorted.values('mean')[:1]), MEAN_INIT), times=Coalesce(Subquery(rating_subquery.order_by().values('user_id') .annotate(count=Count('id')).values('count')), 0)) \ .exclude(user_id__in=contest.rate_exclude.all()) \ .filter(virtual=0).values('id', 'user_id', 'score', 'cumtime', 'tiebreaker', 'last_rating', 'last_mean', 'times') if not contest.rate_all: users = users.filter(submissions__gt=0) if contest.rating_floor is not None: users = users.exclude(last_rating__lt=contest.rating_floor) if contest.rating_ceiling is not None: users = users.exclude(last_rating__gt=contest.rating_ceiling) users = list(users) participation_ids = list(map(itemgetter('id'), users)) user_ids = list(map(itemgetter('user_id'), users)) ranking = list( tie_ranker(users, key=itemgetter('score', 'cumtime', 'tiebreaker'))) old_mean = list(map(itemgetter('last_mean'), users)) times_ranked = list(map(itemgetter('times'), users)) historical_p = [[] for _ in users] user_id_to_idx = {uid: i for i, uid in enumerate(user_ids)} for h in Rating.objects.filter(user_id__in=user_ids) \ .order_by('-contest__end_time') \ .values('user_id', 'performance'): idx = user_id_to_idx[h['user_id']] historical_p[idx].append(h['performance']) rating, mean, performance = recalculate_ratings(ranking, old_mean, times_ranked, historical_p) now = timezone.now() ratings = [ Rating(user_id=i, contest=contest, rating=r, mean=m, performance=perf, last_rated=now, participation_id=pid, rank=z) for i, pid, r, m, perf, z in zip(user_ids, participation_ids, rating, mean, performance, ranking) ] with transaction.atomic(): Rating.objects.bulk_create(ratings) Profile.objects.filter( contest_history__contest=contest, contest_history__virtual=0).update(rating=Subquery( Rating.objects.filter(user=OuterRef('id')).order_by( '-contest__end_time').values('rating')[:1]))
def rate_contest(contest): from judge.models import Rating, Profile rating_subquery = Rating.objects.filter(user=OuterRef('user')) rating_sorted = rating_subquery.order_by('-contest__end_time') users = contest.users.order_by('is_disqualified', '-score', 'cumtime', 'tiebreaker') \ .annotate(submissions=Count('submission'), last_rating=Coalesce(Subquery(rating_sorted.values('rating')[:1]), 1200), volatility=Coalesce(Subquery(rating_sorted.values('volatility')[:1]), 535), times=Coalesce(Subquery(rating_subquery.order_by().values('user_id') .annotate(count=Count('id')).values('count')), 0)) \ .exclude(user_id__in=contest.rate_exclude.all()) \ .filter(virtual=0).values('id', 'user_id', 'score', 'cumtime', 'tiebreaker', 'is_disqualified', 'last_rating', 'volatility', 'times') if not contest.rate_all: users = users.filter(submissions__gt=0) if contest.rating_floor is not None: users = users.exclude(last_rating__lt=contest.rating_floor) if contest.rating_ceiling is not None: users = users.exclude(last_rating__gt=contest.rating_ceiling) users = list(users) participation_ids = list(map(itemgetter('id'), users)) user_ids = list(map(itemgetter('user_id'), users)) is_disqualified = list(map(itemgetter('is_disqualified'), users)) ranking = list( tie_ranker(users, key=itemgetter('score', 'cumtime', 'tiebreaker'))) old_rating = list(map(itemgetter('last_rating'), users)) old_volatility = list(map(itemgetter('volatility'), users)) times_ranked = list(map(itemgetter('times'), users)) rating, volatility = recalculate_ratings(old_rating, old_volatility, ranking, times_ranked, is_disqualified) now = timezone.now() ratings = [ Rating(user_id=i, contest=contest, rating=r, volatility=v, last_rated=now, participation_id=p, rank=z) for i, p, r, v, z in zip(user_ids, participation_ids, rating, volatility, ranking) ] with transaction.atomic(): Rating.objects.bulk_create(ratings) Profile.objects.filter( contest_history__contest=contest, contest_history__virtual=0).update(rating=Subquery( Rating.objects.filter(user=OuterRef('id')).order_by( '-contest__end_time').values('rating')[:1]))
def rate_contest(contest): from judge.models import Rating, Profile rating_subquery = Rating.objects.filter(user=OuterRef('user')) rating_sorted = rating_subquery.order_by('-contest__end_time') users = contest.users.order_by('is_disqualified', '-score', 'cumtime', 'tiebreaker') \ .annotate(submissions=Count('submission'), last_rating=Coalesce(Subquery(rating_sorted.values('rating')[:1]), 1200), volatility=Coalesce(Subquery(rating_sorted.values('volatility')[:1]), 535), times=Coalesce(Subquery(rating_subquery.order_by().values('user_id') .annotate(count=Count('id')).values('count')), 0)) \ .exclude(user_id__in=contest.rate_exclude.all()) \ .filter(virtual=0).values('id', 'user_id', 'score', 'cumtime', 'tiebreaker', 'is_disqualified', 'last_rating', 'volatility', 'times') if not contest.rate_all: users = users.filter(submissions__gt=0) if contest.rating_floor is not None: users = users.exclude(last_rating__lt=contest.rating_floor) if contest.rating_ceiling is not None: users = users.exclude(last_rating__gt=contest.rating_ceiling) users = list(users) participation_ids = list(map(itemgetter('id'), users)) user_ids = list(map(itemgetter('user_id'), users)) is_disqualified = list(map(itemgetter('is_disqualified'), users)) ranking = list( tie_ranker(users, key=itemgetter('score', 'cumtime', 'tiebreaker'))) old_rating = list(map(itemgetter('last_rating'), users)) old_volatility = list(map(itemgetter('volatility'), users)) times_ranked = list(map(itemgetter('times'), users)) rating, volatility = recalculate_ratings(old_rating, old_volatility, ranking, times_ranked, is_disqualified) now = timezone.now() ratings = [ Rating(user_id=i, contest=contest, rating=r, volatility=v, last_rated=now, participation_id=p, rank=z) for i, p, r, v, z in zip(user_ids, participation_ids, rating, volatility, ranking) ] cursor = connection.cursor() cursor.execute( 'CREATE TEMPORARY TABLE _profile_rating_update(id integer, rating integer)' ) cursor.executemany('INSERT INTO _profile_rating_update VALUES (%s, %s)', list(zip(user_ids, rating))) with transaction.atomic(): Rating.objects.filter(contest=contest).delete() Rating.objects.bulk_create(ratings) cursor.execute(''' UPDATE `%s` p INNER JOIN `_profile_rating_update` tmp ON (p.id = tmp.id) SET p.rating = tmp.rating ''' % Profile._meta.db_table) cursor.execute('DROP TABLE _profile_rating_update') cursor.close() return old_rating, old_volatility, ranking, times_ranked, rating, volatility