Skip to content

Commit d30a5d0

Browse files
committed
Speed up achievement scoring.
First get all of the necessary achievement data from the database, then process it and print it to the file. Comparing scoring all course achievements for all users in a course with 5000 users shows a considerable speed improvement. It takes more than three minutes for this with the develop branch, and less than 3 seconds with this pull request. Obviously the generated scoring files are identical.
1 parent 0cdd913 commit d30a5d0

1 file changed

Lines changed: 31 additions & 38 deletions

File tree

lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,20 @@ sub score_handler ($c) {
234234
my $scope = $c->param('action.score.scope');
235235
my @achievementsToScore = $scope eq 'all' ? @{ $c->{allAchievementIDs} } : $c->param('selected_achievements');
236236

237+
# First get everything that is needed from the database.
238+
my @achievements = sortAchievements($db->getAchievements(@achievementsToScore));
239+
my @users = $db->getUsersWhere({ user_id => { not_like => 'set_id:%' } }, [qw(section last_name)]);
240+
241+
my %globalUserAchievements = map { $_->user_id => $_ } $db->getGlobalUserAchievementsWhere;
242+
243+
my %userAchievements;
244+
for (@achievements) {
245+
$userAchievements{ $_->user_id }{ $_->achievement_id } = $_
246+
for $db->getUserAchievementsWhere({ achievement_id => $_->achievement_id });
247+
}
248+
237249
# Define file name
238-
my $scoreFileName = $courseName . "_achievement_scores.csv";
250+
my $scoreFileName = $courseName . '_achievement_scores.csv';
239251
my $scoreFilePath = $ce->{courseDirs}{scoring} . '/' . $scoreFileName;
240252

241253
# Back up existing file
@@ -247,60 +259,41 @@ sub score_handler ($c) {
247259
# Check path and open the file
248260
$scoreFilePath = surePathToFile($ce->{courseDirs}{scoring}, $scoreFilePath);
249261

250-
my $SCORE = Mojo::File->new($scoreFilePath)->open('>:encoding(UTF-8)')
251-
or return (0, $c->maketext("Failed to open [_1]", $scoreFilePath));
262+
my $scoreFile = Mojo::File->new($scoreFilePath)->open('>:encoding(UTF-8)')
263+
or return (0, $c->maketext('Failed to open [_1]', $scoreFilePath));
252264

253265
# Print out header info
254-
print $SCORE $c->maketext("username, last name, first name, section, achievement level, achievement score,");
255-
256-
my @achievements = $db->getAchievements(@achievementsToScore);
257-
@achievements = sortAchievements(@achievements);
266+
print $scoreFile $c->maketext('username, last name, first name, section, achievement level, achievement score,');
258267

259268
for my $achievement (@achievements) {
260-
print $SCORE $achievement->achievement_id . ", ";
261-
}
262-
print $SCORE "\n";
263-
264-
my @users = $db->listUsers;
265-
266-
# Get user records
267-
my @userRecords = ();
268-
for my $currentUser (@users) {
269-
my $userObj = $db->getUser($currentUser);
270-
die "Unable to find user object for $currentUser. " unless $userObj;
271-
push(@userRecords, $userObj);
269+
print $scoreFile $achievement->achievement_id . ', ';
272270
}
273-
274-
@userRecords =
275-
sort { (lc($a->section) cmp lc($b->section)) || (lc($a->last_name) cmp lc($b->last_name)) } @userRecords;
271+
print $scoreFile "\n";
276272

277273
# Print out achievement information for each user
278-
for my $userRecord (@userRecords) {
274+
for my $userRecord (@users) {
279275
my $user_id = $userRecord->user_id;
280-
next unless $db->existsGlobalUserAchievement($user_id);
281-
next if ($userRecord->{status} eq 'D' || $userRecord->{status} eq 'A');
282-
print $SCORE "$user_id, $userRecord->{last_name}, $userRecord->{first_name}, $userRecord->{section}, ";
283-
my $globalUserAchievement = $db->getGlobalUserAchievement($user_id);
284-
my $level_id = $globalUserAchievement->level_achievement_id;
285-
$level_id = ' ' unless $level_id;
286-
my $points = $globalUserAchievement->achievement_points;
287-
$points = 0 unless $points;
288-
print $SCORE "$level_id, $points, ";
276+
next if !$globalUserAchievements{$user_id} || $userRecord->{status} eq 'D' || $userRecord->{status} eq 'A';
277+
278+
print $scoreFile "$user_id, $userRecord->{last_name}, $userRecord->{first_name}, $userRecord->{section}, ";
279+
280+
my $level_id = $globalUserAchievements{$user_id}->level_achievement_id || ' ';
281+
my $points = $globalUserAchievements{$user_id}->achievement_points || 0;
282+
print $scoreFile "$level_id, $points, ";
289283

290284
for my $achievement (@achievements) {
291285
my $achievement_id = $achievement->achievement_id;
292-
if ($db->existsUserAchievement($user_id, $achievement_id)) {
293-
my $userAchievement = $db->getUserAchievement($user_id, $achievement_id);
294-
print $SCORE $userAchievement->earned ? "1, " : "0, ";
286+
if ($userAchievements{$user_id}{$achievement_id}) {
287+
print $scoreFile $userAchievements{$user_id}{$achievement_id}->earned ? '1, ' : '0, ';
295288
} else {
296-
print $SCORE ", ";
289+
print $scoreFile ', ';
297290
}
298291
}
299292

300-
print $SCORE "\n";
293+
print $scoreFile "\n";
301294
}
302295

303-
$SCORE->close;
296+
$scoreFile->close;
304297

305298
# Include a download link
306299
return (

0 commit comments

Comments
 (0)