Commit 1be015eb4d8fd5d285e87cae79da7af80114d43b
1 parent
1377962b
Exists in
master
and in
1 other branch
Change catchup to no longer depend on pregenerated prompts
Showing
3 changed files
with
57 additions
and
28 deletions
Show diff stats
app/models/choice.rb
app/models/question.rb
... | ... | @@ -84,16 +84,16 @@ class Question < ActiveRecord::Base |
84 | 84 | |
85 | 85 | until prompt && prompt.active? |
86 | 86 | target = rand |
87 | - prompt_id = nil | |
87 | + left_choice_id = right_choice_id = nil | |
88 | 88 | |
89 | 89 | weighted.each do |item, weight| |
90 | 90 | if target <= weight |
91 | - prompt_id = item | |
91 | + left_choice_id, right_choice_id = item.split(", ") | |
92 | 92 | break |
93 | 93 | end |
94 | 94 | target -= weight |
95 | 95 | end |
96 | - prompt = Prompt.find(prompt_id, :include => ['left_choice', 'right_choice']) | |
96 | + prompt = prompts.find_or_create_by_left_choice_id_and_right_choice_id(left_choice_id, right_choice_id, :include => [{ :left_choice => :item }, { :right_choice => :item }]) | |
97 | 97 | end |
98 | 98 | # check if prompt has two active choices here, maybe we can set this on the prompt level too? |
99 | 99 | prompt |
... | ... | @@ -104,16 +104,31 @@ class Question < ActiveRecord::Base |
104 | 104 | def catchup_prompts_weights |
105 | 105 | weights = Hash.new(0) |
106 | 106 | throttle_min = 0.05 |
107 | - #assuming all prompts exist | |
107 | + sum = 0.0 | |
108 | 108 | |
109 | - #the_prompts = prompts.find(:all, :select => 'id, votes_count') | |
110 | - #We don't really need to instantiate all the objects | |
111 | - the_prompts = ActiveRecord::Base.connection.select_all("SELECT id, votes_count from prompts where question_id =#{self.id}") | |
109 | + prompts.find_each(:select => 'votes_count, left_choice_id, right_choice_id') do |p| | |
110 | + value = [(1.0/ (p.votes.size + 1).to_f).to_f, throttle_min].min | |
111 | + weights["#{p.left_choice_id}, #{p.right_choice_id}"] = value | |
112 | + sum += value | |
113 | + end | |
112 | 114 | |
113 | - the_prompts.each do |p| | |
114 | - weights[p["id"].to_i] = [(1.0/ (p["votes_count"].to_i + 1).to_f).to_f, throttle_min].min | |
115 | + # This will not run once all prompts have been generated, | |
116 | + # but it prevents us from having to pregenerate all possible prompts | |
117 | + if weights.size < choices.size ** 2 - choices.size | |
118 | + choices.each do |l| | |
119 | + choices.each do |r| | |
120 | + if l.id == r.id | |
121 | + next | |
122 | + end | |
123 | + if !weights.has_key?("#{l.id}, #{r.id}") | |
124 | + weights["#{l.id}, #{r.id}"] = throttle_min | |
125 | + sum+=throttle_min | |
126 | + end | |
127 | + end | |
128 | + end | |
115 | 129 | end |
116 | - normalize!(weights) | |
130 | + | |
131 | + normalize!(weights, sum) | |
117 | 132 | weights |
118 | 133 | end |
119 | 134 | |
... | ... | @@ -148,18 +163,21 @@ class Question < ActiveRecord::Base |
148 | 163 | |
149 | 164 | end |
150 | 165 | |
151 | - def normalize!(weighted) | |
166 | + #passing precomputed sum saves us a traversal through the array | |
167 | + def normalize!(weighted, sum=nil) | |
152 | 168 | if weighted.instance_of?(Hash) |
153 | - sum = weighted.inject(0) do |sum, item_and_weight| | |
154 | - sum += item_and_weight[1] | |
169 | + if sum.nil? | |
170 | + sum = weighted.inject(0) do |sum, item_and_weight| | |
171 | + sum += item_and_weight[1] | |
172 | + end | |
173 | + sum = sum.to_f | |
155 | 174 | end |
156 | - sum = sum.to_f | |
157 | 175 | weighted.each do |item, weight| |
158 | 176 | weighted[item] = weight/sum |
159 | 177 | weighted[item] = 0.0 unless weighted[item].finite? |
160 | 178 | end |
161 | 179 | elsif weighted.instance_of?(Array) |
162 | - sum = weighted.inject(0) {|sum, item| sum += item} | |
180 | + sum = weighted.inject(0) {|sum, item| sum += item} if sum.nil? | |
163 | 181 | weighted.each_with_index do |item, i| |
164 | 182 | weighted[i] = item/sum |
165 | 183 | weighted[i] = 0.0 unless weighted[i].finite? | ... | ... |
lib/tasks/test_api.rake
... | ... | @@ -11,11 +11,14 @@ namespace :test_api do |
11 | 11 | |
12 | 12 | |
13 | 13 | current_user = User.first |
14 | - 3000.times do | |
15 | - question = Question.find(120) # test question change as needed | |
16 | - @p = Prompt.find(question.catchup_choose_prompt_id) | |
17 | - | |
18 | - current_user.record_vote("test_vote", @p, rand(2)) | |
14 | + 1000.times do |n| | |
15 | + puts "#{n} votes completed" if n % 100 == 0 | |
16 | + question = Question.find(214) # test question change as needed | |
17 | + @prompt = question.catchup_choose_prompt | |
18 | + @appearance = current_user.record_appearance(current_user.default_visitor, @prompt) | |
19 | + | |
20 | + direction = (rand(2) == 0) ? "left" : "right" | |
21 | + current_user.record_vote(:prompt => @prompt, :direction => direction, :appearance_lookup => @appearance.lookup) | |
19 | 22 | end |
20 | 23 | |
21 | 24 | end |
... | ... | @@ -183,20 +186,29 @@ namespace :test_api do |
183 | 186 | desc "Dump votes of a question by left vs right id" |
184 | 187 | task(:make_csv => :environment) do |
185 | 188 | |
186 | - q = Question.find(120) | |
189 | + q = Question.find(214) | |
190 | + | |
187 | 191 | |
188 | 192 | the_prompts = q.prompts_hash_by_choice_ids |
189 | 193 | |
190 | 194 | #hash_of_choice_ids_from_left_to_right_to_votes |
191 | 195 | the_hash = {} |
192 | - the_prompts.each do |key, p| | |
193 | - left_id, right_id = key.split(", ") | |
194 | - if not the_hash.has_key?(left_id) | |
195 | - the_hash[left_id] = {} | |
196 | - the_hash[left_id][left_id] = 0 | |
196 | + q.choices.each do |l| | |
197 | + q.choices.each do |r| | |
198 | + next if l.id == r.id | |
199 | + | |
200 | + if not the_hash.has_key?(l.id) | |
201 | + the_hash[l.id] = {} | |
202 | + the_hash[l.id][l.id] = 0 | |
197 | 203 | end |
198 | 204 | |
199 | - the_hash[left_id][right_id] = p.votes.size | |
205 | + p = the_prompts["#{l.id}, #{r.id}"] | |
206 | + if p.nil? | |
207 | + the_hash[l.id][r.id] = 0 | |
208 | + else | |
209 | + the_hash[l.id][r.id] = p.appearances.size | |
210 | + end | |
211 | + end | |
200 | 212 | end |
201 | 213 | |
202 | 214 | the_hash.sort.each do |xval, row| | ... | ... |