Class: Commendo::RubyBacked::ContentSet

Inherits:
Object
  • Object
show all
Defined in:
lib/commendo/ruby-backed/content_set.rb

Constant Summary collapse

DEFAULT_LIMIT =
1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_base, tag_set = nil) ⇒ ContentSet

Returns a new instance of ContentSet.



10
11
12
13
14
15
# File 'lib/commendo/ruby-backed/content_set.rb', line 10

def initialize(key_base, tag_set = nil)
  @resource_group_score = Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = 0 } }
  @key_base = key_base
  @tag_set = tag_set
  @threshold = nil
end

Instance Attribute Details

#key_baseObject

Returns the value of attribute key_base.



6
7
8
# File 'lib/commendo/ruby-backed/content_set.rb', line 6

def key_base
  @key_base
end

#tag_setObject

Returns the value of attribute tag_set.



6
7
8
# File 'lib/commendo/ruby-backed/content_set.rb', line 6

def tag_set
  @tag_set
end

Instance Method Details

#add(resource, *groups) ⇒ Object



22
23
24
25
26
27
28
# File 'lib/commendo/ruby-backed/content_set.rb', line 22

def add(resource, *groups)
  resource = resource.to_s
  groups.map! { |g| g.is_a?(Array) ? g : [g, 1] } #sets default score of 1
  groups.each do |(group, score)|
    @resource_group_score[resource][group.to_s] += score
  end
end

#add_and_calculate(resource, *groups) ⇒ Object



34
35
36
37
# File 'lib/commendo/ruby-backed/content_set.rb', line 34

def add_and_calculate(resource, *groups)
  add(resource, *groups)
  calculate_similarity
end

#add_by_group(group, *resources) ⇒ Object



17
18
19
20
# File 'lib/commendo/ruby-backed/content_set.rb', line 17

def add_by_group(group, *resources)
  resources.map! { |r| r.is_a?(Array) ? r : [r, 1] } #sets default score of 1
  resources.each { |r| add_single(r[0], group, r[1]) }
end

#add_single(resource, group, score) ⇒ Object



30
31
32
# File 'lib/commendo/ruby-backed/content_set.rb', line 30

def add_single(resource, group, score)
  add(resource, [group, score])
end

#calculate_similarity(threshold = nil) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/commendo/ruby-backed/content_set.rb', line 55

def calculate_similarity(threshold = nil)
  @resource_totals = Hash[@resource_group_score.map { |resource, groups| [resource, groups.map { |group, score| score }.inject(0, :+)] }]
  flat_resource_group_score = @resource_group_score.flat_map do |resource, groups|
    groups.map do |group, score|
      [resource, group, score]
    end
  end
  @group_resource_scores = Hash.new { |h, k| h[k] = {} }
  flat_resource_group_score.each { |(resource, group, score)| @group_resource_scores[group][resource] = score }

  @threshold = threshold
end

#calculate_similarity_for_resource(resource, threshold = 0) ⇒ Object



51
52
53
# File 'lib/commendo/ruby-backed/content_set.rb', line 51

def calculate_similarity_for_resource(resource, threshold = 0)
  calculate_similarity(threshold)
end

#delete(resource) ⇒ Object



44
45
46
47
48
49
# File 'lib/commendo/ruby-backed/content_set.rb', line 44

def delete(resource)
  resource = resource.to_s
  @resource_group_score[resource].each { |group,score| @group_resource_scores[group].delete(resource) }
  @resource_group_score.delete(resource)
  @resource_totals.delete(resource)
end

#filtered_similar_to(resource, options = {}) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/commendo/ruby-backed/content_set.rb', line 105

def filtered_similar_to(resource, options = {})
  if @tag_set.nil? || (options[:include].nil? && options[:exclude].nil?) || @tag_set.empty?
    return similar_to(resource, options[:limit] || DEFAULT_LIMIT)
  else
    similar = similar_to(resource)
    limit = options[:limit] || similar.length
    filtered = []
    similar.each do |s|
      return filtered if filtered.length >= limit
      filtered << s if @tag_set.matches(s[:resource], options[:include], options[:exclude])
    end
    return filtered
  end
end

#groups(resource) ⇒ Object



39
40
41
42
# File 'lib/commendo/ruby-backed/content_set.rb', line 39

def groups(resource)
  resource = resource.to_s
  @resource_group_score[resource].keys
end

#remove_from_groups(resource, *groups) ⇒ Object



120
121
122
123
# File 'lib/commendo/ruby-backed/content_set.rb', line 120

def remove_from_groups(resource, *groups)
  resource = resource.to_s
  groups.each { |g| @resource_group_score[resource].delete(g.to_s) }
end

#remove_from_groups_and_calculate(resource, *groups) ⇒ Object



125
126
127
128
# File 'lib/commendo/ruby-backed/content_set.rb', line 125

def remove_from_groups_and_calculate(resource, *groups)
  remove_from_groups(resource, *groups)
  calculate_similarity_for_resource(resource)
end

#similar_to(resource, limit = DEFAULT_LIMIT) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/commendo/ruby-backed/content_set.rb', line 68

def similar_to(resource, limit = DEFAULT_LIMIT)
  if resource.is_a? Array
    return similar_to_array(resource, limit)
  else
    return similar_to_single(resource, limit)
  end
end

#similar_to_array(resources, limit) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'lib/commendo/ruby-backed/content_set.rb', line 76

def similar_to_array(resources, limit)
  similar = resources.flat_map { |r| similar_to_single(r, limit) }
  similar = similar.group_by { |h| h[:resource] }
  similar = similar.map { |resource, sims| {resource: resource, similarity: sims.inject(0) { |sum, sim| sum += sim[:similarity] }} }
  similar.map! { |h| {resource: h[:resource], similarity: h[:similarity].round(3)} }
  similar.keep_if { |sim| @threshold.nil? || sim[:similarity] > @threshold }
  similar = similar.sort_by { |h| [h[:similarity], h[:resource]] }.reverse.first(limit)
  similar
end

#similar_to_single(resource, limit) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/commendo/ruby-backed/content_set.rb', line 86

def similar_to_single(resource, limit)
  resource = resource.to_s
  my_groups = @resource_group_score[resource]

  similar = Hash.new { |h, k| h[k] = 0 }

  my_groups.each do |group, my_score|
    @group_resource_scores[group].each do |other_resource, score|
      next if other_resource == resource
      similarity = (my_score + score).to_f / (@resource_totals[resource] + @resource_totals[other_resource]).to_f
      similar[other_resource] += similarity
    end
  end

  similar = similar.map { |resource, similarity| {resource: resource, similarity: similarity.round(3)} }.sort_by { |h| [h[:similarity], h[:resource]] }.reverse.first(limit)
  similar.keep_if { |sim| @threshold.nil? || sim[:similarity] > @threshold }
  similar
end