I am currently working on an application that matches users based on answers to questions. I implemented my algorithm in regular RoR and ActiveRecord queries, but he does not want to use it. To match one user with 100 other users, you need
Completed 200 OK in 17741ms (Views: 106.1ms | ActiveRecord: 1078.6ms)
on my local machine. But anyway ... Now I want to understand this in raw SQL in order to get better performance. But I'm really having trouble finding SQL queries in SQL queries, etc. Similar calculations are a plus. My head is about to explode, and I donβt even know where to start.
Here is my algorithm:
def match(user) @a_score = (self.actual_score(user).to_f / self.possible_score(user).to_f) * 100 @b_score = (user.actual_score(self).to_f / user.possible_score(self).to_f) * 100 if self.common_questions(user) == [] 0.to_f else match = Math.sqrt(@a_score * @b_score) - (100 / self.common_questions(user).count) if match <= 0 0.to_f else match end end end def possible_score(user) i = 0 self.user_questions.select("question_id, importance").find_each do |n| if user.user_questions.select(:id).find_by_question_id(n.question_id) i += Importance.find_by_id(n.importance).value end end return i end def actual_score(user) i = 0 self.user_questions.select("question_id, importance").includes(:accepted_answers).find_each do |n| @user_answer = user.user_questions.select("answer_id").find_by_question_id(n.question_id) unless @user_answer == nil if n.accepted_answers.select(:answer_id).find_by_answer_id(@user_answer.answer_id) i += Importance.find_by_id(n.importance).value end end end return i end
So, basically the user answers the questions, chooses which answers he accepts, and how important this question is for him. Then the algorithm checks what questions two users have, if user1 answered user2, if so, then user2 is added for each question, which is the result of user1. Also vice versa for the user 2. Divided by the possible score gives a percentage, and both percentages applied to the average average give me one common percentage percentage for both users. Pretty complicated, I know. Tell me if I did not explain it well enough. I just hope I can express this in raw SQL. Performance is all about it.
Here are my database tables:
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "username" varchar(255) DEFAULT '' NOT NULL); (left some unimportant stuff out, it all there in the databse dump i uploaded) CREATE TABLE "user_questions" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "user_id" integer, "question_id" integer, "answer_id" integer(255), "importance" integer, "explanation" text, "private" boolean DEFAULT 'f', "created_at" datetime); CREATE TABLE "accepted_answers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "user_question_id" integer, "answer_id" integer);
I think the top of the SQL query should look something like this:
SELECT u1.id AS user1, u2.id AS user2, COALESCE(SQRT( (100.0*actual_score/possible_score) * (100.0*actual_score/possible_score) ), 0) AS match FROM
But since I'm not a SQL master, I can only do the usual things that my head is about to explode. Hope someone helps me figure this out. Or at least improve your performance somehow! Thank you very much!
EDIT:
So, based on the answer of the wizard, I managed to get a good SQL statement for "possible_score"
SELECT SUM(value) AS sum_id FROM user_questions AS uq1 INNER JOIN importances ON importances.id = uq1.importance INNER JOIN user_questions uq2 ON uq1.question_id = uq2.question_id AND uq2.user_id = 101 WHERE uq1.user_id = 1
I tried to get "actual_score", but that didn't work. My database manager crashed when I executed this.
SELECT SUM(imp.value) AS sum_id FROM user_questions AS uq1 INNER JOIN importances imp ON imp.id = uq1.importance INNER JOIN user_questions uq2 ON uq2.question_id = uq1.question_id AND uq2.user_id = 101 INNER JOIN accepted_answers as ON as.user_question_id = uq1.id AND as.answer_id = uq2.answer_id WHERE uq1.user_id = 1
EDIT2
Ok, I'm an idiot! I can't use the βlikeβ as an alias, of course. Changed it to aa and it worked! W00t!