Skip to content

Commit ff32788

Browse files
committed
Significantly improve leaderboard performance
1 parent 808c94b commit ff32788

File tree

5 files changed

+65
-45
lines changed

5 files changed

+65
-45
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ markdown-it-py==3.0.0
5151
mdurl==0.1.2
5252
numpy==2.3.1
5353
oauthlib==3.2.2
54+
orjson==3.11.4
5455
packaging==25.0
5556
pandas==2.3.1
5657
pillow==10.4.0

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
'djangorestframework',
5252
'drf-yasg',
5353
'isic-challenge-scoring>=5.8',
54+
'orjson',
5455
'requests',
5556
'rules',
5657
# See https://github.com/axnsan12/drf-yasg/issues/874

stade/core/templates/leaderboards.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,25 @@ <h1 class="m-0 text-2xl font-normal text-gray-800">{{ challenge.name }} Leaderbo
8989
<tr class="cursor-pointer transition-colors duration-200 hover:bg-gray-100" @click="toggleDetails({{ submission.id }})" data-submission-id="{{ submission.id }}">
9090
<td class="py-2 px-4 border-b border-gray-300">{{ forloop.counter }}</td>
9191
<td class="py-2 px-4 border-b border-gray-300">
92-
<div>{{ submission.approach.team.name }}</div>
93-
{% if submission.approach.team.institution %}
92+
<div>{{ submission.approach__team__name }}</div>
93+
{% if submission.approach__team__institution %}
9494
<div class="text-sm text-gray-600 mt-0.5">
95-
{{ submission.approach.team.institution }}
95+
{{ submission.approach__team__institution }}
9696
</div>
9797
{% endif %}
9898
</td>
99-
<td class="py-2 px-4 border-b border-gray-300">{{ submission.approach.name }}</td>
99+
<td class="py-2 px-4 border-b border-gray-300">{{ submission.approach__name }}</td>
100100
<td class="py-2 px-4 border-b border-gray-300">
101-
{% if submission.approach.manuscript_url %}
102-
<a href="{{ submission.approach.manuscript_url }}" target="_blank" title="View manuscript">
101+
{% if submission.approach__manuscript_url %}
102+
<a href="{{ submission.approach__manuscript_url }}" target="_blank" title="View manuscript">
103103
<i class="material-icons text-green-600">description</i>
104104
</a>
105105
{% else %}
106106
-
107107
{% endif %}
108108
</td>
109109
<td class="py-2 px-4 border-b border-gray-300">
110-
{% if submission.approach.uses_external_data %}
110+
{% if submission.approach__uses_external_data %}
111111
<div class="flex items-center gap-1">
112112
<i class="material-icons text-orange-600">public</i>
113113
<span>Yes</span>

stade/core/tests/test_leaderboard.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,18 @@ def test_leaderboard_by_approach(task_with_submissions, client):
8181
submissions = resp.context['submissions']
8282
first, second, third, fourth = submissions[:4]
8383

84-
assert first.approach.team.name == 'team_0'
85-
assert first.approach.name == 'approach_0'
86-
assert first.overall_score == 0.95
87-
assert second.approach.team.name == 'team_0'
88-
assert second.approach.name == 'approach_1'
89-
assert second.overall_score == 0.80
90-
assert third.approach.team.name == 'team_1'
91-
assert third.approach.name == 'approach_0'
92-
assert third.overall_score == 0.78
93-
assert fourth.approach.team.name == 'team_3'
94-
assert fourth.approach.name == 'approach_1'
95-
assert fourth.overall_score == 0.60
84+
assert first['approach__team__name'] == 'team_0'
85+
assert first['approach__name'] == 'approach_0'
86+
assert first['overall_score'] == 0.95
87+
assert second['approach__team__name'] == 'team_0'
88+
assert second['approach__name'] == 'approach_1'
89+
assert second['overall_score'] == 0.80
90+
assert third['approach__team__name'] == 'team_1'
91+
assert third['approach__name'] == 'approach_0'
92+
assert third['overall_score'] == 0.78
93+
assert fourth['approach__team__name'] == 'team_3'
94+
assert fourth['approach__name'] == 'approach_1'
95+
assert fourth['overall_score'] == 0.60
9696

9797

9898
@pytest.mark.django_db
@@ -109,12 +109,12 @@ def test_leaderboard_by_team(task_with_submissions, client):
109109
submissions = resp.context['submissions']
110110
first, second, third = submissions[:3]
111111

112-
assert first.approach.team.name == 'team_5'
113-
assert first.approach.name == 'approach_0'
114-
assert first.overall_score == 0.95
115-
assert second.approach.team.name == 'team_6'
116-
assert second.approach.name == 'approach_0'
117-
assert second.overall_score == 0.78
118-
assert third.approach.team.name == 'team_8'
119-
assert third.approach.name == 'approach_1'
120-
assert third.overall_score == 0.60
112+
assert first['approach__team__name'] == 'team_5'
113+
assert first['approach__name'] == 'approach_0'
114+
assert first['overall_score'] == 0.95
115+
assert second['approach__team__name'] == 'team_6'
116+
assert second['approach__name'] == 'approach_0'
117+
assert second['overall_score'] == 0.78
118+
assert third['approach__team__name'] == 'team_8'
119+
assert third['approach__name'] == 'approach_1'
120+
assert third['overall_score'] == 0.60

stade/core/views.py

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import timedelta
2-
import json
32
import logging
43

54
from django.conf import settings
@@ -13,8 +12,10 @@
1312
from django.urls import reverse
1413
from django.utils import timezone
1514
from django.views.decorators.http import require_http_methods
15+
import orjson
1616
import requests
1717
from rules.contrib.views import objectgetter, permission_required
18+
from s3_file_field import S3FileField
1819

1920
from stade.core.forms import (
2021
AcceptInvitationForm,
@@ -68,28 +69,45 @@ def leaderboard_page(request, challenge):
6869
submission_ids = list(submissions_by_approach(active_task.id))
6970

7071
submissions = list(
71-
Submission.objects.defer(None) # avoid n+1 queries on the normally deferred score field
72-
.select_related('approach', 'approach__team', 'creator')
73-
.filter(id__in=submission_ids)
74-
.order_by('-overall_score', 'created')
75-
)[
76-
0:200
77-
] # leaderboards only show the top 200 results
72+
Submission.objects.filter(id__in=submission_ids)
73+
.values(
74+
'id',
75+
'overall_score',
76+
'score',
77+
'created',
78+
'approach__name',
79+
'approach__team__name',
80+
'approach__team__institution',
81+
'approach__uses_external_data',
82+
'approach__manuscript',
83+
)
84+
.order_by('-overall_score', 'created')[:200]
85+
)
7886

87+
field = S3FileField()
7988
for submission in submissions:
80-
if submission.score and isinstance(submission.score, dict):
81-
submission.score_json = json.dumps(submission.score)
89+
score = submission['score']
90+
if score:
91+
if isinstance(score, str):
92+
submission['score_json'] = score
93+
elif isinstance(score, dict):
94+
submission['score_json'] = orjson.dumps(score).decode('utf-8')
95+
else:
96+
submission['score_json'] = '{}'
8297
else:
83-
submission.score_json = '{}'
98+
submission['score_json'] = '{}'
99+
100+
if submission['approach__manuscript']:
101+
submission['approach__manuscript_url'] = field.storage.url(
102+
submission['approach__manuscript']
103+
)
104+
else:
105+
submission['approach__manuscript_url'] = None
84106

85107
stats = {
86108
'total_submissions': len(submissions),
87-
'unique_teams': len(
88-
set(s.approach.team.name for s in submissions if s.approach and s.approach.team)
89-
),
90-
'used_external_data': sum(
91-
1 for s in submissions if s.approach and s.approach.uses_external_data
92-
),
109+
'unique_teams': len(set(s['approach__team__name'] for s in submissions)),
110+
'used_external_data': sum(1 for s in submissions if s['approach__uses_external_data']),
93111
}
94112

95113
return render(

0 commit comments

Comments
 (0)