Skip to content

Commit e805ae9

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

File tree

5 files changed

+66
-45
lines changed

5 files changed

+66
-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: 36 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,6 +12,7 @@
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
1818

@@ -68,28 +68,47 @@ def leaderboard_page(request, challenge):
6868
submission_ids = list(submissions_by_approach(active_task.id))
6969

7070
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
71+
Submission.objects.filter(id__in=submission_ids)
72+
.values(
73+
'id',
74+
'overall_score',
75+
'score',
76+
'created',
77+
'approach__name',
78+
'approach__team__name',
79+
'approach__team__institution',
80+
'approach__uses_external_data',
81+
'approach__manuscript',
82+
)
83+
.order_by('-overall_score', 'created')[:200]
84+
)
7885

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

85108
stats = {
86109
'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-
),
110+
'unique_teams': len(set(s['approach__team__name'] for s in submissions)),
111+
'used_external_data': sum(1 for s in submissions if s['approach__uses_external_data']),
93112
}
94113

95114
return render(

0 commit comments

Comments
 (0)