Commit e532eb9bdb651d881c8f92dacf177cbc2a737e20

Authored by Luke Baker
1 parent 6d3412e9

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
... ...