私は現在、回答された質問に基づいてユーザーを照合するアプリに取り組んでいます。通常の RoR および ActiveRecord クエリで自分のアルゴリズムを認識しましたが、使用するのが遅すぎます。1 人のユーザーと 100 人の他のユーザーを一致させるには
Completed 200 OK in 17741ms (Views: 106.1ms | ActiveRecord: 1078.6ms)
私のローカルマシンで。しかし、それでも...パフォーマンスを向上させるために、生のSQLでこれを実現したいと考えています。しかし、SQLクエリ内のSQLクエリや、このようなものや計算などに頭を悩ませています。頭が爆発しそうで、どこから始めればよいかさえわかりません。
これが私のアルゴリズムです:
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
基本的に、ユーザーは質問に答え、どの回答を受け入れるか、その質問が自分にとってどれほど重要かを選択します。次に、アルゴリズムは 2 人のユーザーに共通する質問をチェックします。ユーザー 1 が回答した場合はユーザー 2 が受け入れます。そうである場合は、質問ごとにユーザー 2 が与えた重要度が追加され、ユーザー 1 が作成したスコアが構成されます。また、user2 の場合は逆です。可能なスコアで割るとパーセンテージが得られ、両方のパーセンテージを幾何平均に適用すると、両方のユーザーの合計一致パーセンテージが得られます。かなり複雑です。私が十分に説明していない場合は教えてください。これを生のSQLで表現できることを願っています。パフォーマンスがすべてです。
ここに私のデータベーステーブルがあります:
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "username" varchar(255) DEFAULT '' NOT NULL); (left some unimportant stuff out, it's 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);
SQL クエリの先頭は次のようになっていると思いますか?
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
しかし、私は SQL マスターではなく、通常のことしかできないので、頭が爆発しそうです。誰かがこれを理解するのを手伝ってくれることを願っています。または、少なくとも私のパフォーマンスを何らかの形で改善してください!本当にありがとう!
編集:
したがって、ウィザードの回答に基づいて、「possible_score」の優れたSQLステートメントを取得できました
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
これで「actual_score」を取得しようとしましたが、うまくいきませんでした。これを実行すると、データベース マネージャーがクラッシュしました。
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
わかりました私はばかです!もちろん、「as」をエイリアスとして使用することはできません。それをaaに変更するとうまくいきました!W00T!