Commit e532eb9bdb651d881c8f92dacf177cbc2a737e20
1 parent
6d3412e9
Exists in
master
and in
1 other branch
refactor random prompt picking
when using catchup and no prompt found, use random prompt
Showing
1 changed file
with
34 additions
and
28 deletions
Show diff stats
app/models/question.rb
@@ -57,7 +57,7 @@ class Question < ActiveRecord::Base | @@ -57,7 +57,7 @@ class Question < ActiveRecord::Base | ||
57 | next_prompt = self.pop_prompt_queue | 57 | next_prompt = self.pop_prompt_queue |
58 | if next_prompt.nil? | 58 | if next_prompt.nil? |
59 | logger.info("DEBUG Catchup prompt cache miss! Nothing in prompt_queue") | 59 | logger.info("DEBUG Catchup prompt cache miss! Nothing in prompt_queue") |
60 | - next_prompt = self.catchup_choose_prompt | 60 | + next_prompt = self.picked_prompt |
61 | record_prompt_cache_miss | 61 | record_prompt_cache_miss |
62 | else | 62 | else |
63 | record_prompt_cache_hit | 63 | record_prompt_cache_hit |
@@ -66,24 +66,18 @@ class Question < ActiveRecord::Base | @@ -66,24 +66,18 @@ class Question < ActiveRecord::Base | ||
66 | return next_prompt | 66 | return next_prompt |
67 | else | 67 | else |
68 | #Standard choose prompt at random | 68 | #Standard choose prompt at random |
69 | - next_prompt = self.picked_prompt | ||
70 | - return next_prompt | 69 | + return self.picked_prompt |
71 | end | 70 | end |
72 | 71 | ||
73 | end | 72 | end |
74 | 73 | ||
75 | - #TODO: generalize for prompts of rank > 2 | ||
76 | - #TODO: add index for rapid finding | ||
77 | - def picked_prompt(rank = 2) | ||
78 | - logger.info "inside Question#picked_prompt" | ||
79 | - raise NotImplementedError.new("Sorry, we currently only support pairwise prompts. Rank of the prompt must be 2.") unless rank == 2 | ||
80 | - begin | ||
81 | - choice_id_array = distinct_array_of_choice_ids(rank) | ||
82 | - @p = prompts.find_or_create_by_left_choice_id_and_right_choice_id(choice_id_array[0], choice_id_array[1], :include => [:left_choice ,:right_choice ]) | ||
83 | - logger.info "#{@p.inspect} is active? #{@p.active?}" | ||
84 | - end until @p.active? | ||
85 | - return @p | ||
86 | - end | 74 | + #TODO: generalize for prompts of rank > 2 |
75 | + def picked_prompt(rank = 2) | ||
76 | + logger.info "inside Question#picked_prompt" | ||
77 | + raise NotImplementedError.new("Sorry, we currently only support pairwise prompts. Rank of the prompt must be 2.") unless rank == 2 | ||
78 | + choice_id_array = distinct_array_of_choice_ids(rank, true) | ||
79 | + prompts.find_or_create_by_left_choice_id_and_right_choice_id(choice_id_array[0], choice_id_array[1], :include => [:left_choice ,:right_choice ]) | ||
80 | + end | ||
87 | 81 | ||
88 | # adapted from ruby cookbook(2006): section 5-11 | 82 | # adapted from ruby cookbook(2006): section 5-11 |
89 | def catchup_choose_prompt | 83 | def catchup_choose_prompt |
@@ -118,6 +112,11 @@ class Question < ActiveRecord::Base | @@ -118,6 +112,11 @@ class Question < ActiveRecord::Base | ||
118 | active_choices = choices.active | 112 | active_choices = choices.active |
119 | active_choice_ids = active_choices.map {|c| c.id} | 113 | active_choice_ids = active_choices.map {|c| c.id} |
120 | sql = "SELECT votes_count, left_choice_id, right_choice_id FROM prompts WHERE question_id = #{self.id} AND left_choice_id IN (#{active_choice_ids.join(',')}) AND right_choice_id IN (#{active_choice_ids.join(',')})" | 114 | sql = "SELECT votes_count, left_choice_id, right_choice_id FROM prompts WHERE question_id = #{self.id} AND left_choice_id IN (#{active_choice_ids.join(',')}) AND right_choice_id IN (#{active_choice_ids.join(',')})" |
115 | + # Warning: lots of memory possibly used here | ||
116 | + # We don't want to use Rails find_each or find_in_batches because | ||
117 | + # it is too slow for close to a million rows. We don't need ActiveRecord | ||
118 | + # objects here. It may be a good idea to update this to grab these in | ||
119 | + # batches. | ||
121 | ActiveRecord::Base.connection.select_all(sql).each do |p| | 120 | ActiveRecord::Base.connection.select_all(sql).each do |p| |
122 | value = [(1.0/ (p['votes_count'].to_i + 1).to_f).to_f, throttle_min].min | 121 | value = [(1.0/ (p['votes_count'].to_i + 1).to_f).to_f, throttle_min].min |
123 | weights[p['left_choice_id']+", "+p['right_choice_id']] = value | 122 | weights[p['left_choice_id']+", "+p['right_choice_id']] = value |
@@ -335,19 +334,26 @@ class Question < ActiveRecord::Base | @@ -335,19 +334,26 @@ class Question < ActiveRecord::Base | ||
335 | end | 334 | end |
336 | 335 | ||
337 | 336 | ||
338 | - def distinct_array_of_choice_ids(rank = 2, only_active = true) | ||
339 | - @choice_ids = choice_ids | ||
340 | - @s = @choice_ids.size | ||
341 | - begin | ||
342 | - index_list = (0...@s).sort_by{rand} | ||
343 | - first_one, second_one = index_list.first, index_list.second | ||
344 | - @the_choice_ids = @choice_ids.values_at(first_one, second_one) | ||
345 | - # @the_choice_ids << choices.active.first(:order => 'RAND()', :select => 'id').id | ||
346 | - # @the_choice_ids << choices.active.last(:order => 'RAND()', :select => 'id').id | ||
347 | - end until (@the_choice_ids.size == rank) | ||
348 | - logger.info "List populated and looks like #{@the_choice_ids.inspect}" | ||
349 | - return @the_choice_ids.to_a | ||
350 | - end | 337 | + def distinct_array_of_choice_ids(rank = 2, only_active = true) |
338 | + count = (only_active) ? choices.active.count : choices.count | ||
339 | + | ||
340 | + found_choices = [] | ||
341 | + rank.times do | ||
342 | + # select only active choices? | ||
343 | + conditions = (only_active) ? ['active = ?', true] : [''] | ||
344 | + # if we've already found some, make sure we don't find them again | ||
345 | + if found_choices.count > 0 | ||
346 | + conditions[0] += ' AND id NOT IN (?)' | ||
347 | + conditions.push found_choices | ||
348 | + end | ||
349 | + | ||
350 | + found_choices.push choices.find(:first, | ||
351 | + :select => 'id', | ||
352 | + :conditions => conditions, | ||
353 | + :offset => rand(count - found_choices.count)).id | ||
354 | + end | ||
355 | + return found_choices | ||
356 | + end | ||
351 | 357 | ||
352 | def picked_prompt_id | 358 | def picked_prompt_id |
353 | picked_prompt.id | 359 | picked_prompt.id |