Commit db7025249b45bdfc86b05f91e24b408ccfb46d79
1 parent
03abebca
Exists in
staging
and in
26 other branches
profile-suggestions: create only a small and fixed number of suggestions
Showing
2 changed files
with
140 additions
and
73 deletions
Show diff stats
app/models/profile_suggestion.rb
| ... | ... | @@ -8,6 +8,10 @@ class ProfileSuggestion < ActiveRecord::Base |
| 8 | 8 | profile_suggestion.suggestion_type = self.suggestion.class.to_s |
| 9 | 9 | end |
| 10 | 10 | |
| 11 | + after_destroy do |profile_suggestion| | |
| 12 | + self.class.generate_profile_suggestions(profile_suggestion.person) | |
| 13 | + end | |
| 14 | + | |
| 11 | 15 | acts_as_having_settings :field => :categories |
| 12 | 16 | |
| 13 | 17 | validate :must_be_a_valid_category, :on => :create |
| ... | ... | @@ -50,11 +54,11 @@ class ProfileSuggestion < ActiveRecord::Base |
| 50 | 54 | communities_with_common_tags |
| 51 | 55 | ] |
| 52 | 56 | |
| 53 | - # Number of suggestions | |
| 54 | - N_SUGGESTIONS = 30 | |
| 57 | + # Number of suggestions by rule | |
| 58 | + SUGGESTIONS_BY_RULE = 10 | |
| 55 | 59 | |
| 56 | - # Number max of attempts | |
| 57 | - MAX_ATTEMPTS = N_SUGGESTIONS * 2 | |
| 60 | + # Minimum number of suggestions | |
| 61 | + MIN_LIMIT = 15 | |
| 58 | 62 | |
| 59 | 63 | # Number of friends in common |
| 60 | 64 | COMMON_FRIENDS = 2 |
| ... | ... | @@ -66,8 +70,12 @@ class ProfileSuggestion < ActiveRecord::Base |
| 66 | 70 | COMMON_TAGS = 2 |
| 67 | 71 | |
| 68 | 72 | def self.register_suggestions(person, suggested_profiles, rule) |
| 73 | + already_suggested_profiles = person.profile_suggestions.map(&:suggestion_id).join(',') | |
| 74 | + suggested_profiles = suggested_profiles.where("profiles.id NOT IN (#{already_suggested_profiles})") if already_suggested_profiles.present? | |
| 75 | + suggested_profiles = suggested_profiles.limit(SUGGESTIONS_BY_RULE) | |
| 76 | + return if suggested_profiles.blank? | |
| 69 | 77 | counter = rule.split(/.*_with_/).last |
| 70 | - suggested_profiles.find_each do |suggested_profile| | |
| 78 | + suggested_profiles.each do |suggested_profile| | |
| 71 | 79 | suggestion = person.profile_suggestions.find_or_initialize_by_suggestion_id(suggested_profile.id) |
| 72 | 80 | suggestion.send(counter+'=', suggested_profile.common_count.to_i) |
| 73 | 81 | suggestion.save! |
| ... | ... | @@ -87,6 +95,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 87 | 95 | |
| 88 | 96 | def self.people_with_common_friends(person) |
| 89 | 97 | person_friends = person.friends.map(&:id) |
| 98 | + return [] if person_friends.blank? | |
| 90 | 99 | person.environment.people. |
| 91 | 100 | select("profiles.*, suggestions.count AS common_count"). |
| 92 | 101 | joins(" |
| ... | ... | @@ -100,6 +109,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 100 | 109 | |
| 101 | 110 | def self.people_with_common_communities(person) |
| 102 | 111 | person_communities = person.communities.map(&:id) |
| 112 | + return [] if person_communities.blank? | |
| 103 | 113 | person.environment.people. |
| 104 | 114 | select("profiles.*, suggestions.count AS common_count"). |
| 105 | 115 | joins(" |
| ... | ... | @@ -115,6 +125,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 115 | 125 | |
| 116 | 126 | def self.people_with_common_tags(person) |
| 117 | 127 | profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) |
| 128 | + return [] if profile_tags.blank? | |
| 118 | 129 | person.environment.people. |
| 119 | 130 | select("profiles.*, suggestions.count as common_count"). |
| 120 | 131 | joins(" |
| ... | ... | @@ -132,6 +143,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 132 | 143 | |
| 133 | 144 | def self.communities_with_common_friends(person) |
| 134 | 145 | person_friends = person.friends.map(&:id) |
| 146 | + return [] if person_friends.blank? | |
| 135 | 147 | person.environment.communities. |
| 136 | 148 | select("profiles.*, suggestions.count AS common_count"). |
| 137 | 149 | joins(" |
| ... | ... | @@ -147,6 +159,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 147 | 159 | |
| 148 | 160 | def self.communities_with_common_tags(person) |
| 149 | 161 | profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) |
| 162 | + return [] if profile_tags.blank? | |
| 150 | 163 | person.environment.communities. |
| 151 | 164 | select("profiles.*, suggestions.count AS common_count"). |
| 152 | 165 | joins(" |
| ... | ... | @@ -164,15 +177,17 @@ class ProfileSuggestion < ActiveRecord::Base |
| 164 | 177 | |
| 165 | 178 | def disable |
| 166 | 179 | self.enabled = false |
| 167 | - self.save | |
| 180 | + self.save! | |
| 181 | + self.class.generate_profile_suggestions(self.person) | |
| 168 | 182 | end |
| 169 | 183 | |
| 170 | 184 | def self.generate_all_profile_suggestions |
| 171 | 185 | Delayed::Job.enqueue(ProfileSuggestion::GenerateAllJob.new) unless ProfileSuggestion::GenerateAllJob.exists? |
| 172 | 186 | end |
| 173 | 187 | |
| 174 | - def self.generate_profile_suggestions(person_id) | |
| 175 | - Delayed::Job.enqueue ProfileSuggestionsJob.new(person_id) unless ProfileSuggestionsJob.exists?(person_id) | |
| 188 | + def self.generate_profile_suggestions(person, force = false) | |
| 189 | + return if person.profile_suggestions.enabled.count >= MIN_LIMIT && !force | |
| 190 | + Delayed::Job.enqueue ProfileSuggestionsJob.new(person.id) unless ProfileSuggestionsJob.exists?(person.id) | |
| 176 | 191 | end |
| 177 | 192 | |
| 178 | 193 | class GenerateAllJob |
| ... | ... | @@ -181,7 +196,7 @@ class ProfileSuggestion < ActiveRecord::Base |
| 181 | 196 | end |
| 182 | 197 | |
| 183 | 198 | def perform |
| 184 | - Person.find_each {|person| ProfileSuggestion.generate_profile_suggestions(person.id) } | |
| 199 | + Person.find_each {|person| ProfileSuggestion.generate_profile_suggestions(person) } | |
| 185 | 200 | end |
| 186 | 201 | end |
| 187 | 202 | ... | ... |
test/unit/profile_suggestion_test.rb
| ... | ... | @@ -221,84 +221,136 @@ class ProfileSuggestionTest < ActiveSupport::TestCase |
| 221 | 221 | ProfileSuggestion.calculate_suggestions(person) |
| 222 | 222 | end |
| 223 | 223 | |
| 224 | - should 'update existing person suggestion when the number of common friends increase' do | |
| 225 | - suggested_person = create_user('test_user').person | |
| 226 | - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_friends => 2) | |
| 227 | - | |
| 228 | - friend = create_user('friend').person | |
| 229 | - friend2 = create_user('friend2').person | |
| 230 | - friend3 = create_user('friend2').person | |
| 231 | - person.add_friend friend | |
| 232 | - person.add_friend friend2 | |
| 233 | - person.add_friend friend3 | |
| 234 | - | |
| 235 | - friend.add_friend suggested_person | |
| 236 | - | |
| 237 | - suggested_person.add_friend friend | |
| 238 | - suggested_person.add_friend friend2 | |
| 239 | - suggested_person.add_friend friend3 | |
| 240 | - | |
| 241 | - assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do | |
| 242 | - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_friends(person), 'people_with_common_friends') | |
| 224 | +#FIXME This might not be necessary anymore... | |
| 225 | +# should 'update existing person suggestion when the number of common friends increase' do | |
| 226 | +# suggested_person = create_user('test_user').person | |
| 227 | +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_friends => 2) | |
| 228 | +# | |
| 229 | +# friend = create_user('friend').person | |
| 230 | +# friend2 = create_user('friend2').person | |
| 231 | +# friend3 = create_user('friend2').person | |
| 232 | +# person.add_friend friend | |
| 233 | +# person.add_friend friend2 | |
| 234 | +# person.add_friend friend3 | |
| 235 | +# | |
| 236 | +# friend.add_friend suggested_person | |
| 237 | +# | |
| 238 | +# suggested_person.add_friend friend | |
| 239 | +# suggested_person.add_friend friend2 | |
| 240 | +# suggested_person.add_friend friend3 | |
| 241 | +# | |
| 242 | +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do | |
| 243 | +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_friends(person), 'people_with_common_friends') | |
| 244 | +# end | |
| 245 | +# end | |
| 246 | +# | |
| 247 | +# should 'update existing person suggestion when the number of common communities increase' do | |
| 248 | +# suggested_person = create_user('test_user').person | |
| 249 | +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_communities => 1) | |
| 250 | +# | |
| 251 | +# community.add_member person | |
| 252 | +# community.add_member suggested_person | |
| 253 | +# | |
| 254 | +# community2 = fast_create(Community) | |
| 255 | +# community2.add_member person | |
| 256 | +# community2.add_member suggested_person | |
| 257 | +# | |
| 258 | +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_communities', 1 do | |
| 259 | +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_communities(person), 'people_with_common_communities') | |
| 260 | +# end | |
| 261 | +# end | |
| 262 | +# | |
| 263 | +# should 'update existing person suggestion when the number of common tags increase' do | |
| 264 | +# suggested_person = create_user('test_user').person | |
| 265 | +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_tags => 1) | |
| 266 | +# | |
| 267 | +# create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') | |
| 268 | +# create(Article, :created_by => suggested_person, :profile => suggested_person, :tag_list => 'first-tag, second-tag, third-tag') | |
| 269 | +# | |
| 270 | +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do | |
| 271 | +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_tags(person), 'people_with_common_tags') | |
| 272 | +# end | |
| 273 | +# end | |
| 274 | +# | |
| 275 | +# should 'update existing community suggestion when the number of common friends increase' do | |
| 276 | +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_friends => 1) | |
| 277 | +# | |
| 278 | +# member1 = create_user('member1').person | |
| 279 | +# member2 = create_user('member2').person | |
| 280 | +# | |
| 281 | +# person.add_friend member1 | |
| 282 | +# person.add_friend member2 | |
| 283 | +# | |
| 284 | +# community.add_member member1 | |
| 285 | +# community.add_member member2 | |
| 286 | +# | |
| 287 | +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do | |
| 288 | +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_friends(person), 'communities_with_common_friends') | |
| 289 | +# end | |
| 290 | +# | |
| 291 | +# end | |
| 292 | +# | |
| 293 | +# should 'update existing community suggestion when the number of common tags increase' do | |
| 294 | +# other_person = create_user('test_user').person | |
| 295 | +# | |
| 296 | +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_tags => 1) | |
| 297 | +# | |
| 298 | +# create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') | |
| 299 | +# create(Article, :created_by => other_person, :profile => community, :tag_list => 'first-tag, second-tag, third-tag') | |
| 300 | +# | |
| 301 | +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do | |
| 302 | +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_tags(person), 'communities_with_common_tags') | |
| 303 | +# end | |
| 304 | +# end | |
| 305 | + | |
| 306 | + should 'register only new suggestions' do | |
| 307 | + person = create_user('person').person | |
| 308 | + ProfileSuggestion::SUGGESTIONS_BY_RULE.times do | |
| 309 | + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Person)) | |
| 243 | 310 | end |
| 244 | - end | |
| 245 | 311 | |
| 246 | - should 'update existing person suggestion when the number of common communities increase' do | |
| 247 | - suggested_person = create_user('test_user').person | |
| 248 | - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_communities => 1) | |
| 312 | + person.reload | |
| 313 | + new_suggestion = fast_create(Person) | |
| 314 | + ids = (person.suggested_people + [new_suggestion]).map(&:id).join(',') | |
| 315 | + suggested_profiles = Profile.select('profiles.*, profiles.id as common_count').where("profiles.id IN (#{ids})") | |
| 249 | 316 | |
| 250 | - community.add_member person | |
| 251 | - community.add_member suggested_person | |
| 252 | - | |
| 253 | - community2 = fast_create(Community) | |
| 254 | - community2.add_member person | |
| 255 | - community2.add_member suggested_person | |
| 256 | - | |
| 257 | - assert_difference 'ProfileSuggestion.find(suggestion.id).common_communities', 1 do | |
| 258 | - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_communities(person), 'people_with_common_communities') | |
| 317 | + assert_difference 'ProfileSuggestion.count', 1 do | |
| 318 | + ProfileSuggestion.register_suggestions(person, suggested_profiles, 'people_with_common_friends') | |
| 259 | 319 | end |
| 260 | 320 | end |
| 261 | 321 | |
| 262 | - should 'update existing person suggestion when the number of common tags increase' do | |
| 263 | - suggested_person = create_user('test_user').person | |
| 264 | - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_tags => 1) | |
| 265 | - | |
| 266 | - create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') | |
| 267 | - create(Article, :created_by => suggested_person, :profile => suggested_person, :tag_list => 'first-tag, second-tag, third-tag') | |
| 268 | - | |
| 269 | - assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do | |
| 270 | - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_tags(person), 'people_with_common_tags') | |
| 322 | + should 'calculate new suggestions when number of available suggestions reaches the min_limit' do | |
| 323 | + person = create_user('person').person | |
| 324 | + (ProfileSuggestion::MIN_LIMIT + 1).times do | |
| 325 | + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) | |
| 271 | 326 | end |
| 272 | - end | |
| 273 | - | |
| 274 | - should 'update existing community suggestion when the number of common friends increase' do | |
| 275 | - suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_friends => 1) | |
| 276 | - | |
| 277 | - member1 = create_user('member1').person | |
| 278 | - member2 = create_user('member2').person | |
| 279 | 327 | |
| 280 | - person.add_friend member1 | |
| 281 | - person.add_friend member2 | |
| 328 | + ProfileSuggestion.expects(:calculate_suggestions) | |
| 282 | 329 | |
| 283 | - community.add_member member1 | |
| 284 | - community.add_member member2 | |
| 330 | + person.profile_suggestions.enabled.last.disable | |
| 331 | + person.profile_suggestions.enabled.last.destroy | |
| 332 | + process_delayed_job_queue | |
| 333 | + end | |
| 285 | 334 | |
| 286 | - assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do | |
| 287 | - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_friends(person), 'communities_with_common_friends') | |
| 335 | + should 'not create job to calculate new suggestions if there is already enough suggestions enabled' do | |
| 336 | + person = create_user('person').person | |
| 337 | + (ProfileSuggestion::MIN_LIMIT + 1).times do | |
| 338 | + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) | |
| 288 | 339 | end |
| 289 | 340 | |
| 341 | + ProfileSuggestion.expects(:calculate_suggestions).never | |
| 342 | + ProfileSuggestion.generate_profile_suggestions(person) | |
| 343 | + process_delayed_job_queue | |
| 290 | 344 | end |
| 291 | 345 | |
| 292 | - should 'update existing community suggestion when the number of common tags increase' do | |
| 293 | - other_person = create_user('test_user').person | |
| 294 | - | |
| 295 | - suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_tags => 1) | |
| 296 | - | |
| 297 | - create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') | |
| 298 | - create(Article, :created_by => other_person, :profile => community, :tag_list => 'first-tag, second-tag, third-tag') | |
| 299 | - | |
| 300 | - assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do | |
| 301 | - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_tags(person), 'communities_with_common_tags') | |
| 346 | + should 'be able to force suggestions calculation' do | |
| 347 | + person = create_user('person').person | |
| 348 | + (ProfileSuggestion::MIN_LIMIT + 1).times do | |
| 349 | + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) | |
| 302 | 350 | end |
| 351 | + | |
| 352 | + ProfileSuggestion.expects(:calculate_suggestions) | |
| 353 | + ProfileSuggestion.generate_profile_suggestions(person, true) | |
| 354 | + process_delayed_job_queue | |
| 303 | 355 | end |
| 304 | 356 | end | ... | ... |