running_stat 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ec11d286e66a056fc873beecd760b3916008ea2
4
- data.tar.gz: 99915adeadbbe43c59c190a5392f46c85f438126
3
+ metadata.gz: 692e627aba71ce44c80b57d406c85dd69f38edfc
4
+ data.tar.gz: 0caada43394fd224b1e8932958bbe18ed1fd4815
5
5
  SHA512:
6
- metadata.gz: dc655fd6ca351e6bf5a3d9fb4331b2e704b22cd0a3551dd914ae025ad558b2a261dad16edbf7964578fc4945a7d3b54da013fc9040e83c8fb2929483f4e1e416
7
- data.tar.gz: 5ed907c0cc481824640b8df911556c509616132e991ab1a9fecf347cb54c22398132990906bff31d6a6fac7cb1d5f7848b92509486dc3b9e620043867cd6178d
6
+ metadata.gz: b173a92b2b32bd8decf100e7c4f4f79b179ff4681839abbb4fcb390db1553d411d9ac552779279ee9d4ac8cef767d133f6780dbce8e8927c8ecb8a8560e8f965
7
+ data.tar.gz: fe7e30605e41b8e2980fa9760b7f722e33f8bf6f1f7b2dec5a7c56ced7c8dd648e345d4a90ac5b676e624d605582e54b8fdd602c67e10f21e0b0a8d6cd703aee
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ## [0.1.0] - 2016-01-12
6
+ ### Added
7
+ - n/a
8
+
9
+ ### Changed
10
+ - All keys for each metric combined into a single redis hash
11
+ (this will null out old metrics)
12
+
5
13
  ## [0.0.1] - 2016-01-11
6
14
  ### Added
7
15
  - Initial release
data/README.md CHANGED
@@ -8,6 +8,8 @@ RunningStat provides distributed redis-backed data buckets on which various stat
8
8
 
9
9
  The algorithm used is based on Knuth's TAOCP and is numerically stable; a brief writeup is available on Wikipedia under [Algorithms for calculating online variances](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm).
10
10
 
11
+ RunningStat supports pretty much all versions of ruby, including MRI 1.8.7, 1.9.3, 2.2, and JRuby 1.7/9k.
12
+
11
13
  Disclaimer: Because it uses atomic Lua scripting, RunningStat requires redis 2.6+.
12
14
 
13
15
 
data/lib/running_stat.rb CHANGED
@@ -2,6 +2,7 @@ require 'running_stat/version'
2
2
 
3
3
  require 'redis'
4
4
 
5
+ require 'running_stat/redis_backend'
5
6
  require 'running_stat/lua/push_datum'
6
7
  require 'running_stat/lua/variance'
7
8
  require 'running_stat/insufficient_data_error'
@@ -22,26 +23,26 @@ class RunningStat
22
23
 
23
24
  # Adds a piece of numerical data to the dataset's stats
24
25
  def push(datum)
25
- redis.eval(Lua::PUSH_DATUM, [count_key, mean_key, sum_sq_diff_key], [Float(datum)])
26
+ redis.eval(Lua::PUSH_DATUM, [bucket_key], [Float(datum)])
26
27
  rescue ArgumentError => e
27
28
  raise InvalidDataError.new(e) # datum was non-numerical
28
29
  end
29
30
 
30
31
  # Returns the number of data points seen, or 0 if the stat does not exist
31
32
  def cardinality
32
- redis.get(count_key).to_i
33
+ redis.hget(bucket_key, RedisBackend::COUNT_FIELD).to_i
33
34
  end
34
35
 
35
36
  # Returns the arithmetic mean of data points seen, or 0.0 if non-existent
36
37
  def mean
37
- redis.get(mean_key).to_f
38
+ redis.hget(bucket_key, RedisBackend::MEAN_FIELD).to_f
38
39
  end
39
40
 
40
41
  # Returns the sample variance of the dataset so far, or raises
41
42
  # an InsufficientDataError if insufficient data (< 2 datapoints)
42
43
  # has been pushed
43
44
  def variance
44
- redis.eval(Lua::VARIANCE, [count_key, sum_sq_diff_key], []).to_f
45
+ redis.eval(Lua::VARIANCE, [bucket_key], []).to_f
45
46
  rescue Redis::CommandError => e
46
47
  raise InsufficientDataError.new(e) # only CommandError possible
47
48
  end
@@ -55,7 +56,7 @@ class RunningStat
55
56
 
56
57
  # Resets the stat to reflect an empty dataset
57
58
  def flush
58
- redis.del(count_key, mean_key, sum_sq_diff_key)
59
+ redis.del(bucket_key)
59
60
  end
60
61
 
61
62
  private
@@ -64,15 +65,7 @@ class RunningStat
64
65
  @redis || Redis.current
65
66
  end
66
67
 
67
- def count_key
68
- "#{BASE_KEY}:#{@data_bucket}:count"
69
- end
70
-
71
- def mean_key
72
- "#{BASE_KEY}:#{@data_bucket}:mean"
73
- end
74
-
75
- def sum_sq_diff_key
76
- "#{BASE_KEY}:#{@data_bucket}:sum_sq_diff"
68
+ def bucket_key
69
+ "#{BASE_KEY}:#{@data_bucket}"
77
70
  end
78
71
  end
@@ -1,11 +1,10 @@
1
1
  require 'digest/sha1'
2
+ require 'running_stat/redis_backend'
2
3
 
3
4
  class RunningStat
4
5
  module Lua
5
6
  # Keys:
6
- # count - the dataset cardinality
7
- # mean - the mean of the dataset so far
8
- # m2 - the running sum of the squares of the differences of the dataset
7
+ # bucket - the hash corresponding to the dataset metric
9
8
  # Arguments:
10
9
  # datum - the number to be added to the dataset
11
10
  # Effects:
@@ -13,17 +12,15 @@ class RunningStat
13
12
  # Returns:
14
13
  # nothing
15
14
  PUSH_DATUM = <<-EOLUA
16
- local count_key = KEYS[1]
17
- local mean_key = KEYS[2]
18
- local m2_key = KEYS[3]
15
+ local bucket_key = KEYS[1]
19
16
  local datum = ARGV[1]
20
17
 
21
- local mean = tonumber(redis.call("GET", mean_key)) or 0.0
18
+ local mean = tonumber(redis.call("HGET", bucket_key, "#{RedisBackend::MEAN_FIELD}")) or 0.0
22
19
  local delta = datum - mean
23
20
 
24
- local count = redis.call("INCR", count_key)
25
- mean = redis.call("INCRBYFLOAT", mean_key, tostring(delta / count))
26
- redis.call("INCRBYFLOAT", m2_key, tostring(delta * (datum - mean)))
21
+ local count = redis.call("HINCRBY", bucket_key, "#{RedisBackend::COUNT_FIELD}", 1)
22
+ mean = redis.call("HINCRBYFLOAT", bucket_key, "#{RedisBackend::MEAN_FIELD}", tostring(delta / count))
23
+ redis.call("HINCRBYFLOAT", bucket_key, "#{RedisBackend::M2_FIELD}", tostring(delta * (datum - mean)))
27
24
  EOLUA
28
25
 
29
26
  PUSH_DATUM_SHA1 = Digest::SHA1.hexdigest(PUSH_DATUM).freeze
@@ -1,11 +1,11 @@
1
1
  require 'digest/sha1'
2
+ require 'running_stat/redis_backend'
2
3
  require 'running_stat/insufficient_data_error'
3
4
 
4
5
  class RunningStat
5
6
  module Lua
6
7
  # Keys:
7
- # count - the dataset cardinality
8
- # m2 - the running sum of the squares of the differences of the dataset
8
+ # bucket - the hash corresponding to the dataset metric
9
9
  # Arguments:
10
10
  # nothing
11
11
  # Effects:
@@ -13,14 +13,14 @@ class RunningStat
13
13
  # Returns:
14
14
  # the sample variance of the dataset, as a stringified float
15
15
  VARIANCE = <<-EOLUA
16
- local count_key = KEYS[1]
17
- local m2_key = KEYS[2]
16
+ local bucket_key = KEYS[1]
18
17
 
19
- local count = tonumber(redis.call("GET", count_key)) or 0
18
+ local values = redis.call("HMGET", bucket_key, "#{RedisBackend::COUNT_FIELD}", "#{RedisBackend::M2_FIELD}")
19
+ local count = tonumber(values[1]) or 0
20
20
  if count < 2 then
21
21
  return redis.error_reply("#{InsufficientDataError::ERROR_STRING}")
22
22
  else
23
- local m2 = tonumber(redis.call("GET", m2_key)) or 0.0
23
+ local m2 = tonumber(values[2]) or 0.0
24
24
  return tostring(m2 / (count - 1))
25
25
  end
26
26
  EOLUA
@@ -0,0 +1,10 @@
1
+ class RunningStat
2
+ module RedisBackend
3
+ # fields within the metric's redis hash
4
+ COUNT_FIELD = :c # the dataset cardinality
5
+ MEAN_FIELD = :m # the arithmetic mean of the dataset
6
+ M2_FIELD = :m2 # the running sum of the squares of the differences of the dataset
7
+
8
+ # TODO: implement global redis set/get
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  class RunningStat
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: running_stat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anuj Das
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-11 00:00:00.000000000 Z
11
+ date: 2016-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -89,6 +89,7 @@ files:
89
89
  - lib/running_stat/invalid_data_error.rb
90
90
  - lib/running_stat/lua/push_datum.rb
91
91
  - lib/running_stat/lua/variance.rb
92
+ - lib/running_stat/redis_backend.rb
92
93
  - lib/running_stat/version.rb
93
94
  - running_stat.gemspec
94
95
  homepage: https://www.github.com/anujdas/running_stat