Class: RecsysNeedsFinder

Inherits:
Object
  • Object
show all
Defined in:
app/workers/recsys_needs_finder.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_id) ⇒ RecsysNeedsFinder

Returns a new instance of RecsysNeedsFinder.



6
7
8
# File 'app/workers/recsys_needs_finder.rb', line 6

def initialize(user_id)
  @user = User.find(user_id)
end

Instance Attribute Details

#userObject (readonly)

Returns the value of attribute user.



4
5
6
# File 'app/workers/recsys_needs_finder.rb', line 4

def user
  @user
end

Instance Method Details

#callObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/workers/recsys_needs_finder.rb', line 10

def call
  # Get max network_id to use latest recommendations
  network_id = RecsysResult.distinct.pluck(:network_id).max

  needs = (list_recommended_needs.sample(1) + latest_needs.sample(1))
  needs_scores = get_score
  scores = needs.map { |need| needs_scores[need.id] || 0.0 }

  return if needs.empty?

  begin
    RecsysMailer.recsys_recommendation(@user, network_id, needs, scores).deliver
  rescue Postmark::InactiveRecipientError
    # TODO: Add a flag that user email is wrong somehow and to not send emails again to this user.
  end

  # Update has_seen relation (unless needs.empty?)
  needs.each { |need| @user.add_edge(need, 'has_seen') }
end

#get_scoreObject



75
76
77
78
79
80
81
82
83
84
# File 'app/workers/recsys_needs_finder.rb', line 75

def get_score
  # Get scores of recommended needs
  results = RecsysResult
            .where(sourceable_node: @user)
            .where(targetable_node_type: 'Need')
            .pluck(:targetable_node_id, :value)
            .uniq

  Hash[results]
end

#latest_needsObject



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'app/workers/recsys_needs_finder.rb', line 30

def latest_needs
  # # Only select project ids for which the need has not already been seen
  # # There should not be a RecsysDatum instance for the given user, need and 'has_seen' relation.
  # has_seen_need_ids = RecsysDatum
  #                       .where(
  #                         sourceable_node: user,
  #                         targetable_node_type: 'Need',
  #                         relation_type: 'has_seen')
  #                       .pluck(:targetable_node_id)
  # # Get two latest project needs as default in case the user has no recommendations
  # # We need to be careful and join with project here because of orphaned Need records
  # latest_project_ids = Need
  #   .joins(:project)
  #   .where
  #   .not(id: has_seen_need_ids)
  #   .order(id: :desc)
  #   .pluck(:project_id)
  #   .uniq
  # latest_needs = latest_project_ids.map { |project_id|
  #   Need.where(project_id: project_id).where.not(id: has_seen_need_ids).order(id: :desc) }
  # ten_latest_needs = latest_needs.flatten.sample(10)
  Need.last(10).to_a
end


64
65
66
67
68
69
70
71
72
73
# File 'app/workers/recsys_needs_finder.rb', line 64

def list_recommended_needs
  # Sort recommended needs by decreasing value (needs_ids is ordered this way)
  # We need to be careful here to avoid orphaned needs
  # Furthermore, some recommended needs don't concern projects
  # TODO: handle other types of needs
  Need
    .where(id: needs_ids)
    .to_a
    # .sort_by { |need| needs_ids.find_index(need.id) }
end

#needs_idsObject



54
55
56
57
58
59
60
61
62
# File 'app/workers/recsys_needs_finder.rb', line 54

def needs_ids
  # Get list of recommended needs and send email
  @needs_ids ||= RecsysResult
    .where(sourceable_node: @user)
    .where(targetable_node_type: 'Need')
    .order(value: :desc)
    .pluck(:targetable_node_id)
    .uniq
end