Commit a7431d97424fcbc61b0f4a47bcb055ad6bd5b522

Authored by Luke Baker
1 parent 92dd57ad

generate 1000 prompts at once

only generate prompts if cache is less than 90% full
app/models/question.rb
@@ -80,26 +80,29 @@ class Question < ActiveRecord::Base @@ -80,26 +80,29 @@ class Question < ActiveRecord::Base
80 end 80 end
81 81
82 # adapted from ruby cookbook(2006): section 5-11 82 # adapted from ruby cookbook(2006): section 5-11
83 - def catchup_choose_prompt 83 + def catchup_choose_prompt(num=1000)
84 weighted = catchup_prompts_weights 84 weighted = catchup_prompts_weights
85 # Rand returns a number from 0 - 1, so weighted needs to be normalized 85 # Rand returns a number from 0 - 1, so weighted needs to be normalized
86 - prompt = nil  
87 -  
88 - until prompt && prompt.active?  
89 - target = rand  
90 - left_choice_id = right_choice_id = nil  
91 -  
92 - weighted.each do |item, weight|  
93 - if target <= weight  
94 - left_choice_id, right_choice_id = item.split(", ")  
95 - break 86 + generated_prompts = []
  87 +
  88 + num.times do
  89 + prompt = nil
  90 + until prompt && prompt.active?
  91 + target = rand
  92 + left_choice_id = right_choice_id = nil
  93 +
  94 + weighted.each do |item, weight|
  95 + if target <= weight
  96 + left_choice_id, right_choice_id = item.split(", ")
  97 + break
  98 + end
  99 + target -= weight
96 end 100 end
97 - target -= weight 101 + 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 }])
98 end 102 end
99 - 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 }]) 103 + generated_prompts.push prompt
100 end 104 end
101 - # check if prompt has two active choices here, maybe we can set this on the prompt level too?  
102 - prompt 105 + generated_prompts
103 end 106 end
104 107
105 108
@@ -472,9 +475,18 @@ class Question &lt; ActiveRecord::Base @@ -472,9 +475,18 @@ class Question &lt; ActiveRecord::Base
472 end 475 end
473 476
474 def add_prompt_to_queue 477 def add_prompt_to_queue
475 - prompt = self.catchup_choose_prompt  
476 - $redis.rpush(self.pq_key, prompt.id)  
477 - prompt 478 + num_prompts = 1000
  479 + # if less than 90% full, regenerate prompts
  480 + if $redis.llen(self.pq_key) < num_prompts * 0.9
  481 + prompts = self.catchup_choose_prompt(num_prompts)
  482 + # clear list
  483 + $redis.ltrim(self.pq_key, 0, 0)
  484 + $redis.lpop(self.pq_key)
  485 + prompts.each do |prompt|
  486 + $redis.rpush(self.pq_key, prompt.id)
  487 + end
  488 + return prompts
  489 + end
478 end 490 end
479 491
480 def pop_prompt_queue 492 def pop_prompt_queue
lib/tasks/test_api.rake
@@ -39,7 +39,7 @@ namespace :test_api do @@ -39,7 +39,7 @@ namespace :test_api do
39 1000.times do |n| 39 1000.times do |n|
40 puts "#{n} votes completed" if n % 100 == 0 40 puts "#{n} votes completed" if n % 100 == 0
41 question = Question.find(214) # test question change as needed 41 question = Question.find(214) # test question change as needed
42 - @prompt = question.catchup_choose_prompt 42 + @prompt = question.catchup_choose_prompt(1).first
43 @appearance = current_user.record_appearance(current_user.default_visitor, @prompt) 43 @appearance = current_user.record_appearance(current_user.default_visitor, @prompt)
44 44
45 direction = (rand(2) == 0) ? "left" : "right" 45 direction = (rand(2) == 0) ? "left" : "right"
spec/models/question_spec.rb
@@ -55,7 +55,7 @@ describe Question do @@ -55,7 +55,7 @@ describe Question do
55 end 55 end
56 56
57 it "should choose an active prompt using catchup algorithm" do 57 it "should choose an active prompt using catchup algorithm" do
58 - prompt = @question.catchup_choose_prompt 58 + prompt = @question.catchup_choose_prompt(1).first
59 prompt.active?.should == true 59 prompt.active?.should == true
60 end 60 end
61 61
@@ -242,7 +242,7 @@ describe Question do @@ -242,7 +242,7 @@ describe Question do
242 # Sanity check 242 # Sanity check
243 @catchup_q.choices.size.should == 100 243 @catchup_q.choices.size.should == 100
244 244
245 - prompt = @catchup_q.catchup_choose_prompt 245 + prompt = @catchup_q.catchup_choose_prompt(1).first
246 prompt.active?.should == true 246 prompt.active?.should == true
247 end 247 end
248 248
@@ -282,36 +282,10 @@ describe Question do @@ -282,36 +282,10 @@ describe Question do
282 prompt.should_not == nil 282 prompt.should_not == nil
283 prompt.active?.should == true 283 prompt.active?.should == true
284 end 284 end
285 - it "should return prompts from the queue in FIFO order" do  
286 - @catchup_q.clear_prompt_queue  
287 - @catchup_q.pop_prompt_queue.should == nil  
288 -  
289 - prompt1 = @catchup_q.add_prompt_to_queue  
290 - prompt2 = @catchup_q.add_prompt_to_queue  
291 - prompt3 = @catchup_q.add_prompt_to_queue  
292 -  
293 - prompt_1 = @catchup_q.pop_prompt_queue  
294 - prompt_2 = @catchup_q.pop_prompt_queue  
295 - prompt_3 = @catchup_q.pop_prompt_queue  
296 -  
297 -  
298 - prompt_1.should == prompt1  
299 - prompt_2.should == prompt2  
300 - prompt_3.should == prompt3  
301 -  
302 - # there is a small probability that the catchup algorithm  
303 - # choose two prompts that are indeed equal  
304 - prompt_1.should_not == prompt_2  
305 - prompt_1.should_not == prompt_3  
306 - prompt_2.should_not == prompt_3  
307 -  
308 -  
309 - @catchup_q.pop_prompt_queue.should == nil  
310 - end  
311 it "should not return prompts from queue that are deactivated" do 285 it "should not return prompts from queue that are deactivated" do
312 @catchup_q.clear_prompt_queue 286 @catchup_q.clear_prompt_queue
313 @catchup_q.pop_prompt_queue.should == nil 287 @catchup_q.pop_prompt_queue.should == nil
314 - prompt1 = @catchup_q.add_prompt_to_queue 288 + prompt1 = @catchup_q.add_prompt_to_queue.first
315 289
316 prompt = Prompt.find(prompt1) 290 prompt = Prompt.find(prompt1)
317 prompt.left_choice.deactivate! 291 prompt.left_choice.deactivate!