Scoreboard optimizations (#1475)

* The top scoreboard endpoint `/api/v1/scoreboard/top/<count>` is now more performant (3x) due to better response generation

In local testing I went from 3.5s to 1.2s.
This commit is contained in:
Kevin Chung
2020-06-04 14:46:36 -04:00
committed by GitHub
parent 409473acc0
commit 56d7b6d6d0
2 changed files with 26 additions and 30 deletions

View File

@@ -9,7 +9,8 @@
* Add `/api/v1/challenges?view=admin` to allow admin users to see all challenges regardless of their visibility state * Add `/api/v1/challenges?view=admin` to allow admin users to see all challenges regardless of their visibility state
* Add `/api/v1/users?view=admin` to allow admin users to see all users regardless of their hidden/banned state * Add `/api/v1/users?view=admin` to allow admin users to see all users regardless of their hidden/banned state
* Add `/api/v1/teams?view=admin` to allow admin users to see all teams regardless of their hidden/banned state * Add `/api/v1/teams?view=admin` to allow admin users to see all teams regardless of their hidden/banned state
* The scoreboard endpoint `/api/v1/scoreboard` is now significantly more performant due to better response generation * The scoreboard endpoint `/api/v1/scoreboard` is now significantly more performant (20x) due to better response generation
* The top scoreboard endpoint `/api/v1/scoreboard/top/<count>` is now more performant (3x) due to better response generation
* The scoreboard endpoint `/api/v1/scoreboard` will no longer show hidden/banned users in a non-hidden team * The scoreboard endpoint `/api/v1/scoreboard` will no longer show hidden/banned users in a non-hidden team
**Deployment** **Deployment**

View File

@@ -1,3 +1,5 @@
from collections import defaultdict
from flask_restx import Namespace, Resource from flask_restx import Namespace, Resource
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
@@ -119,15 +121,11 @@ class ScoreboardDetail(Resource):
solves = solves.all() solves = solves.all()
awards = awards.all() awards = awards.all()
for i, team in enumerate(team_ids): # Build a mapping of accounts to their solves and awards
response[i + 1] = { solves = solves + awards
"id": standings[i].account_id, solves_mapper = defaultdict(list)
"name": standings[i].name,
"solves": [],
}
for solve in solves: for solve in solves:
if solve.account_id == team: solves_mapper[solve.account_id].append(
response[i + 1]["solves"].append(
{ {
"challenge_id": solve.challenge_id, "challenge_id": solve.challenge_id,
"account_id": solve.account_id, "account_id": solve.account_id,
@@ -137,20 +135,17 @@ class ScoreboardDetail(Resource):
"date": isoformat(solve.date), "date": isoformat(solve.date),
} }
) )
for award in awards:
if award.account_id == team: # Sort all solves by date
response[i + 1]["solves"].append( for team_id in solves_mapper:
{ solves_mapper[team_id] = sorted(
"challenge_id": None, solves_mapper[team_id], key=lambda k: k["date"]
"account_id": award.account_id,
"team_id": award.team_id,
"user_id": award.user_id,
"value": award.value,
"date": isoformat(award.date),
}
)
response[i + 1]["solves"] = sorted(
response[i + 1]["solves"], key=lambda k: k["date"]
) )
for i, team in enumerate(team_ids):
response[i + 1] = {
"id": standings[i].account_id,
"name": standings[i].name,
"solves": solves_mapper.get(standings[i].account_id, []),
}
return {"success": True, "data": response} return {"success": True, "data": response}