CSC/ECE 517 Spring 2014/oss E1404 mnp: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
Line 61: Line 61:


=== Objective 3: Get scores of all the users for a given course ===
=== Objective 3: Get scores of all the users for a given course ===
A new view was required since this view did not exist previously. A new link has been added to the user's homepage.
A new view was required since this view did not exist previously. This view will be displayed on clicking on the View Scores option in the Actions panel of the courses as highlighted below:
[[File:]]
[[File:Course_scores.jpg]]


We needed to write a method and add a view that computed and displayed the scores of all users that have enrolled in a course.
We needed to write a method and add a view that computed and displayed the scores of all users that have enrolled in a course. We added a method named view_course_scores in the grades_controller.rb. This method does the following steps:
* Creates an empty hash.
* Runs a single SQL query as below:
SELECT assignments.name, user_id, questionnaire_type, avg(score), min(score), max(score) from
(SELECT r.id as response_id, team_id, u.name as user_id, (SUM(weight*score)*100)/(sum(weight)*max_question_score) as score, t.parent_id as assignment_id, qs.type as questionnaire_type
FROM scores s ,responses r, response_maps rm, questions q, questionnaires qs , users u, teams_users tu , teams t
WHERE  rm.id = r.map_id AND r.id=s.response_id AND q.id = s.question_id AND qs.id = q.questionnaire_id    AND tu.team_id = rm.reviewee_id  AND tu.team_id = t.id AND tu.user_id=u.id group by r.id
) as participant_score_aggregate, assignments
WHERE assignments.id = participant_score_aggregate.assignment_id
and assignments.course_id = ? group by assignment_id, questionnaire_type
 
The course id is passed as a parameter to this query.
 
* The result returned from the query is used to populate the hash. This hash is then used to display the different parts of the view as shown below:
[[File:Course_scores_view]]
 
=== Guidelines followed ===
The following guidelines were followed wherever possible to achieve the above objectives, especially keeping in mind that they must make the implementation fast:
* Single query instead of multiple queries.
* Queries extracted outside loops.
* Avoided method calls where values could be obtained in the same SQL query itself.


== Future work ==
== Future work ==

Revision as of 05:42, 30 March 2014

Improvement to View Scores

Introduction

Background

The scores are calculated for multiple views. This code is very slow because:

  • Separate db queries are used for each rubric that has been filled out by anyone associated with the assignment; these queries are made sequentially while the HTML page is being written
  • HTML for the whole page is generated, largely by controller methods, before anything is displayed.

This code needs to be made faster.

What needs to be done

Classes

models/score.rb controllers/grades_controller.rb

Objectives

  • Participant.find(user id).scores # should return a Hash or new object, with a single database query. This method should return the scores of a participant from all the assignments in which the participant has submitted.
  • assignment.scores # should return a Hash or new object, with a single database query. This method should return scores of all the participants in an assignment.
  • course.scores # should return a Hash. This method should return scores of all the participants enrolled in a course.

Design and implementation

Objective 1: Get scores of all the assignments for a given user

A new view was required since this view did not exist previously. A new link has been added to the user's homepage.

We needed to write a method and add a view that computed and displayed the scores of a user across all the assignments user has participated in. We added a new method all_scores in the grades_controller.rb. This method executes the following steps:

  • :Executes the below sql query:

SELECT assignments.name, questionnaire_type, avg(score), min(score), max(score) FROM (SELECT r.id as response_id, team_id, tu.user_id as user_id, (SUM(weight*score)*100)/(sum(weight)*max_question_score) as score, parent_id as assignment_id, qs.type as questionnaire_type FROM scores s ,responses r, response_maps rm, questions q, questionnaires qs , teams_users tu , teams t WHERE rm.id = r.map_id AND r.id=s.response_id AND q.id = s.question_id AND qs.id = q.questionnaire_id AND tu.team_id = rm.reviewee_id AND tu.team_id = t.id group by r.id) as participant_score_aggregate, assignments WHERE assignments.id = participant_score_aggregate.assignment_id and user_id = ? group by assignment_id, questionnaire_type


The user_id is of the current user is passed as a parameter to this query.

  • From the result obtained from the above query, we create a hash of the format:

assignment name => questionnaire type

questionnaire type is again a hash that is of the form: questionnaire type => score_type

The score type is a hash that takes any of the three values [avg, max and min] as key the value will be the actual score. Once the hash is created and populated accordingly, this hash is used by the view to display to the user as below:

Objective 2: Improve the speed of getting scores for a given assignment

This part is computed in the get_scores method of the assignment.rb. Previously this code worked as follows:

  • For each participant the participant.get_scores is called for each question. For all quiz questionnaires taken by the participant, get all the quiz responses. Create a hash and store the score computed by calling Score.compute_quiz_scores. The total score is then calculated and stored in the hash by calling compute_total_score for each participant.
  • For all teams that participated in this assignment, get the scores into the hash by calling Score.compute_scores for each assessment and questions.

This method is specifically slow because the first step consists of several substeps, performed inside a big loop. Each of them might query the database adding to the time taken.

We refactored this code to have the following steps:

  • Created an empty hash before hand.
  • Run a single SQL query that will return all the data required by the hash.
  • Loop through the result set to populate the hash.

This speeds up the code since there is only a single SQL query that will get executed. The loop runs only for the number of rows in the returned result set. This means that the loop runs only for the assignment submissions that got scored. The query is outside the loop and hence reduces the time required.

Objective 3: Get scores of all the users for a given course

A new view was required since this view did not exist previously. This view will be displayed on clicking on the View Scores option in the Actions panel of the courses as highlighted below:

We needed to write a method and add a view that computed and displayed the scores of all users that have enrolled in a course. We added a method named view_course_scores in the grades_controller.rb. This method does the following steps:

  • Creates an empty hash.
  • Runs a single SQL query as below:

SELECT assignments.name, user_id, questionnaire_type, avg(score), min(score), max(score) from (SELECT r.id as response_id, team_id, u.name as user_id, (SUM(weight*score)*100)/(sum(weight)*max_question_score) as score, t.parent_id as assignment_id, qs.type as questionnaire_type FROM scores s ,responses r, response_maps rm, questions q, questionnaires qs , users u, teams_users tu , teams t WHERE rm.id = r.map_id AND r.id=s.response_id AND q.id = s.question_id AND qs.id = q.questionnaire_id AND tu.team_id = rm.reviewee_id AND tu.team_id = t.id AND tu.user_id=u.id group by r.id ) as participant_score_aggregate, assignments WHERE assignments.id = participant_score_aggregate.assignment_id and assignments.course_id = ? group by assignment_id, questionnaire_type

The course id is passed as a parameter to this query.

  • The result returned from the query is used to populate the hash. This hash is then used to display the different parts of the view as shown below:

File:Course scores view

Guidelines followed

The following guidelines were followed wherever possible to achieve the above objectives, especially keeping in mind that they must make the implementation fast:

  • Single query instead of multiple queries.
  • Queries extracted outside loops.
  • Avoided method calls where values could be obtained in the same SQL query itself.

Future work