Class: Weathercock::Scorer
- Inherits:
-
Object
- Object
- Weathercock::Scorer
- Defined in:
- lib/weathercock/scorer.rb
Constant Summary collapse
- BUCKET_COUNT =
90- BUCKET_TTLS =
{ hours: BUCKET_COUNT * 3600, days: BUCKET_COUNT * 86400, months: BUCKET_COUNT * 30 * 86400 }.freeze
Instance Method Summary collapse
- #hit(id, event, increment: 1) ⇒ Object
- #hit_count(id, event, **window) ⇒ Object
- #hit_counts(event, ids:, **window) ⇒ Object
-
#initialize(klass:) ⇒ Scorer
constructor
A new instance of Scorer.
- #rank(id, event, **window) ⇒ Object
- #remove_hits(id, event) ⇒ Object
- #top(event, limit:, decay_factor: nil, **window) ⇒ Object
Constructor Details
#initialize(klass:) ⇒ Scorer
Returns a new instance of Scorer.
13 14 15 16 |
# File 'lib/weathercock/scorer.rb', line 13 def initialize(klass:) @redis = Weathercock.config.redis @key_builder = KeyBuilder.new(namespace: Weathercock.config.namespace, klass: klass) end |
Instance Method Details
#hit(id, event, increment: 1) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/weathercock/scorer.rb', line 18 def hit(id, event, increment: 1) now = Time.now base = @key_builder.base(event) @redis.pipelined do |p| p.call("ZINCRBY", @key_builder.total(base), increment, id.to_s) BUCKET_TTLS.each do |type, ttl| key = @key_builder.bucket(base, type, now) p.call("ZINCRBY", key, increment, id.to_s) p.call("EXPIRE", key, ttl) end end end |
#hit_count(id, event, **window) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/weathercock/scorer.rb', line 45 def hit_count(id, event, **window) base = @key_builder.base(event) if window.empty? score = @redis.call("ZSCORE", @key_builder.total(base), id.to_s) return score ? score.to_i : 0 end dest = union(event, window) score = @redis.call("ZSCORE", dest, id.to_s) score ? score.to_i : 0 end |
#hit_counts(event, ids:, **window) ⇒ Object
73 74 75 76 77 78 |
# File 'lib/weathercock/scorer.rb', line 73 def hit_counts(event, ids:, **window) base = @key_builder.base(event) dest = window.empty? ? @key_builder.total(base) : union(event, window) scores = @redis.call("ZMSCORE", dest, *ids.map(&:to_s)) ids.zip(scores).to_h { |id, score| [id.to_s, (score || "0").to_i] } end |
#rank(id, event, **window) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/weathercock/scorer.rb', line 66 def rank(id, event, **window) base = @key_builder.base(event) dest = window.empty? ? @key_builder.total(base) : union(event, window) r = @redis.call("ZREVRANK", dest, id.to_s) r ? r + 1 : nil end |
#remove_hits(id, event) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/weathercock/scorer.rb', line 32 def remove_hits(id, event) base = @key_builder.base(event) @redis.pipelined do |p| p.call("ZREM", @key_builder.total(base), id.to_s) BUCKET_TTLS.each_key do |type| @key_builder.window_keys(base, type, BUCKET_COUNT).each do |key| p.call("ZREM", key, id.to_s) end end end end |
#top(event, limit:, decay_factor: nil, **window) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/weathercock/scorer.rb', line 57 def top(event, limit:, decay_factor: nil, **window) base = @key_builder.base(event) stop = limit ? limit - 1 : -1 return @redis.call("ZRANGE", @key_builder.total(base), 0, stop, "REV") if window.empty? dest = union(event, window, decay_factor: decay_factor) @redis.call("ZRANGE", dest, 0, stop, "REV") end |