Commit a7431d97424fcbc61b0f4a47bcb055ad6bd5b522
1 parent
92dd57ad
Exists in
master
and in
1 other branch
generate 1000 prompts at once
only generate prompts if cache is less than 90% full
Showing
3 changed files
with
34 additions
and
48 deletions
Show diff stats
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 < ActiveRecord::Base | @@ -472,9 +475,18 @@ class Question < 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! |