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 | 57 | next_prompt = self.pop_prompt_queue |
58 | 58 | if next_prompt.nil? |
59 | 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 | 61 | record_prompt_cache_miss |
62 | 62 | else |
63 | 63 | record_prompt_cache_hit |
... | ... | @@ -66,24 +66,18 @@ class Question < ActiveRecord::Base |
66 | 66 | return next_prompt |
67 | 67 | else |
68 | 68 | #Standard choose prompt at random |
69 | - next_prompt = self.picked_prompt | |
70 | - return next_prompt | |
69 | + return self.picked_prompt | |
71 | 70 | end |
72 | 71 | |
73 | 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 | 82 | # adapted from ruby cookbook(2006): section 5-11 |
89 | 83 | def catchup_choose_prompt |
... | ... | @@ -118,6 +112,11 @@ class Question < ActiveRecord::Base |
118 | 112 | active_choices = choices.active |
119 | 113 | active_choice_ids = active_choices.map {|c| c.id} |
120 | 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 | 120 | ActiveRecord::Base.connection.select_all(sql).each do |p| |
122 | 121 | value = [(1.0/ (p['votes_count'].to_i + 1).to_f).to_f, throttle_min].min |
123 | 122 | weights[p['left_choice_id']+", "+p['right_choice_id']] = value |
... | ... | @@ -335,19 +334,26 @@ class Question < ActiveRecord::Base |
335 | 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 | 358 | def picked_prompt_id |
353 | 359 | picked_prompt.id | ... | ... |