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,38 +121,31 @@ class ScoreboardDetail(Resource):
solves = solves.all() solves = solves.all()
awards = awards.all() awards = awards.all()
# Build a mapping of accounts to their solves and awards
solves = solves + awards
solves_mapper = defaultdict(list)
for solve in solves:
solves_mapper[solve.account_id].append(
{
"challenge_id": solve.challenge_id,
"account_id": solve.account_id,
"team_id": solve.team_id,
"user_id": solve.user_id,
"value": solve.challenge.value,
"date": isoformat(solve.date),
}
)
# Sort all solves by date
for team_id in solves_mapper:
solves_mapper[team_id] = sorted(
solves_mapper[team_id], key=lambda k: k["date"]
)
for i, team in enumerate(team_ids): for i, team in enumerate(team_ids):
response[i + 1] = { response[i + 1] = {
"id": standings[i].account_id, "id": standings[i].account_id,
"name": standings[i].name, "name": standings[i].name,
"solves": [], "solves": solves_mapper.get(standings[i].account_id, []),
} }
for solve in solves:
if solve.account_id == team:
response[i + 1]["solves"].append(
{
"challenge_id": solve.challenge_id,
"account_id": solve.account_id,
"team_id": solve.team_id,
"user_id": solve.user_id,
"value": solve.challenge.value,
"date": isoformat(solve.date),
}
)
for award in awards:
if award.account_id == team:
response[i + 1]["solves"].append(
{
"challenge_id": None,
"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"]
)
return {"success": True, "data": response} return {"success": True, "data": response}