merry_go_round 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,6 +43,16 @@ module MerryGoRound
43
43
 
44
44
  # Aggregate existing aggregations (i.e. hour -> day)
45
45
  def compound
46
+ # Get list of known keys
47
+ keys = Aggregation.select('DISTINCT(key) AS key').collect(&:key)
48
+
49
+ # Aggregate each key
50
+ keys.each do |key|
51
+ compound_key(key)
52
+ end
53
+ end
54
+
55
+ def compound_key(key)
46
56
  now = Time.now.utc
47
57
 
48
58
  # Loop through all of the granularities except for the first one
@@ -50,46 +60,60 @@ module MerryGoRound
50
60
  # Skip minutes since the Redis aggregator does those
51
61
  next if index == 0
52
62
 
63
+ # Get starting point
64
+ start = start_timestamp(key, granularity).to_i
65
+
53
66
  # Time interval for granularity
67
+ # TODO: Use `window` instead of `seconds`
54
68
  interval = seconds(granularity)
55
69
 
56
70
  # Get the previous granularity
57
71
  prev_gran = MerryGoRound.granularities[index - 1]
58
72
 
59
- # Get where we left off for this granularity
60
- results = Aggregation.select('MAX(timestamp) AS timestamp, key').where(granularity: prev_gran).group(:key).order('timestamp DESC')
61
-
62
73
  # Loop through the results
63
- results.each do |result|
64
- timestamp = result.timestamp.utc.to_i
65
- while timestamp < now.to_i
66
- range = window(granularity, Time.at(timestamp).utc)
67
- break unless range.first < now and range.last < now
68
-
69
- # Check time interval to see if we have enough data to do this granularity
70
- break if Aggregation.where('key = ? AND granularity = ? AND timestamp = ?', result.key, granularity, range.first).first
74
+ while start < now.to_i
75
+ range = window(granularity, Time.at(start).utc)
76
+ break unless range.first < now
71
77
 
72
- children = Aggregation.where('key = ? AND granularity = ? AND timestamp >= ? AND timestamp <= ?', result.key, prev_gran, range.first, range.last).order('timestamp ASC')
73
- break unless children.length > 0
78
+ # Check time interval to see if we have enough data to do this granularity
79
+ break if Aggregation.where('key = ? AND granularity = ? AND timestamp = ?', key, granularity, range.first).first
74
80
 
75
- # Get the aggregated value
76
- # TODO: This should probably done in SQL
77
- value = children.collect(&:value).reduce(:+)
81
+ children = Aggregation.where('key = ? AND granularity = ? AND timestamp >= ? AND timestamp <= ?', key, prev_gran, range.first, range.last).order('timestamp ASC')
82
+ break unless children.length > 0
78
83
 
79
- # Create the aggregation
80
- agg = Aggregation.create(key: result.key, value: value, granularity: granularity, timestamp: range.first)
84
+ # Get the aggregated value
85
+ # TODO: This should probably done in SQL
86
+ value = children.collect(&:value).reduce(:+)
81
87
 
82
- # Associate the children with their parent
83
- children.each do |child|
84
- child.parent_id = agg.id
85
- child.save
86
- end
88
+ # Create the aggregation
89
+ agg = Aggregation.create(key: key, value: value, granularity: granularity, timestamp: range.first)
87
90
 
88
- # Increment the timestamp
89
- timestamp += interval
91
+ # Associate the children with their parent
92
+ children.each do |child|
93
+ child.parent_id = agg.id
94
+ child.save
90
95
  end
96
+
97
+ # Increment the timestamp
98
+ start += interval
91
99
  end
92
100
  end
93
101
  end
102
+
103
+ def start_timestamp(key, granularity)
104
+ # Search at this level
105
+ result = Aggregation.select('MAX(timestamp) AS timestamp').where(key: key, granularity: granularity).order('timestamp DESC').first
106
+ if result and result.timestamp
107
+ # TODO: Possibily add 1
108
+ return result.timestamp
109
+ end
110
+
111
+ # Go down a level
112
+ prev_gran = MerryGoRound.granularities[MerryGoRound.granularities.index(granularity) - 1]
113
+ result = Aggregation.select('MIN(timestamp) AS timestamp').where(key: key, granularity: prev_gran).order('timestamp ASC').first
114
+ return result.timestamp if result and result.timestamp
115
+
116
+ nil
117
+ end
94
118
  end
95
119
  end
@@ -1,3 +1,3 @@
1
1
  module MerryGoRound
2
- VERSION = '0.0.5'
2
+ VERSION = '0.0.6'
3
3
  end
File without changes
@@ -0,0 +1,179 @@
1
+ key,value,timestamp,granularity
2
+ vote.create,17,2013-02-13 00:01:00,minute
3
+ vote.create,5,2013-02-13 00:02:00,minute
4
+ vote.create,15,2013-02-13 00:03:00,minute
5
+ vote.create,9,2013-02-13 00:04:00,minute
6
+ vote.create,6,2013-02-13 00:05:00,minute
7
+ vote.create,4,2013-02-13 00:06:00,minute
8
+ vote.create,6,2013-02-13 00:07:00,minute
9
+ vote.create,2,2013-02-13 00:08:00,minute
10
+ vote.create,2,2013-02-13 00:09:00,minute
11
+ vote.create,3,2013-02-13 00:10:00,minute
12
+ vote.create,8,2013-02-13 00:11:00,minute
13
+ vote.create,8,2013-02-13 00:12:00,minute
14
+ vote.create,7,2013-02-13 00:13:00,minute
15
+ vote.create,15,2013-02-13 00:14:00,minute
16
+ vote.create,10,2013-02-13 00:15:00,minute
17
+ vote.create,2,2013-02-13 00:16:00,minute
18
+ vote.create,15,2013-02-13 00:17:00,minute
19
+ vote.create,13,2013-02-13 00:18:00,minute
20
+ vote.create,24,2013-02-13 00:19:00,minute
21
+ vote.create,20,2013-02-13 00:20:00,minute
22
+ vote.create,19,2013-02-13 00:21:00,minute
23
+ vote.create,24,2013-02-13 00:22:00,minute
24
+ vote.create,17,2013-02-13 00:23:00,minute
25
+ vote.create,9,2013-02-13 00:24:00,minute
26
+ vote.create,16,2013-02-13 00:25:00,minute
27
+ vote.create,12,2013-02-13 00:26:00,minute
28
+ vote.create,18,2013-02-13 00:27:00,minute
29
+ vote.create,19,2013-02-13 00:28:00,minute
30
+ vote.create,11,2013-02-13 00:29:00,minute
31
+ vote.create,8,2013-02-13 00:30:00,minute
32
+ vote.create,2,2013-02-13 00:31:00,minute
33
+ vote.create,6,2013-02-13 00:32:00,minute
34
+ vote.create,12,2013-02-13 00:33:00,minute
35
+ vote.create,11,2013-02-13 00:34:00,minute
36
+ vote.create,8,2013-02-13 00:35:00,minute
37
+ vote.create,3,2013-02-13 00:36:00,minute
38
+ vote.create,3,2013-02-13 00:37:00,minute
39
+ vote.create,2,2013-02-13 00:38:00,minute
40
+ vote.create,16,2013-02-13 00:39:00,minute
41
+ vote.create,16,2013-02-13 00:40:00,minute
42
+ vote.create,25,2013-02-13 00:41:00,minute
43
+ vote.create,25,2013-02-13 00:42:00,minute
44
+ vote.create,14,2013-02-13 00:43:00,minute
45
+ vote.create,11,2013-02-13 00:44:00,minute
46
+ vote.create,10,2013-02-13 00:45:00,minute
47
+ vote.create,3,2013-02-13 00:46:00,minute
48
+ vote.create,12,2013-02-13 00:47:00,minute
49
+ vote.create,12,2013-02-13 00:48:00,minute
50
+ vote.create,25,2013-02-13 00:49:00,minute
51
+ vote.create,36,2013-02-13 00:50:00,minute
52
+ vote.create,32,2013-02-13 00:51:00,minute
53
+ vote.create,18,2013-02-13 00:52:00,minute
54
+ vote.create,13,2013-02-13 00:53:00,minute
55
+ vote.create,9,2013-02-13 00:54:00,minute
56
+ vote.create,21,2013-02-13 00:55:00,minute
57
+ vote.create,19,2013-02-13 00:56:00,minute
58
+ vote.create,10,2013-02-13 00:57:00,minute
59
+ vote.create,11,2013-02-13 00:58:00,minute
60
+ vote.create,8,2013-02-13 00:59:00,minute
61
+ vote.create,27,2013-02-13 01:00:00,minute
62
+ vote.create,14,2013-02-13 01:01:00,minute
63
+ vote.create,14,2013-02-13 01:02:00,minute
64
+ vote.create,12,2013-02-13 01:03:00,minute
65
+ vote.create,1,2013-02-13 01:04:00,minute
66
+ vote.create,4,2013-02-13 01:05:00,minute
67
+ vote.create,20,2013-02-13 01:06:00,minute
68
+ vote.create,15,2013-02-13 01:07:00,minute
69
+ vote.create,6,2013-02-13 01:08:00,minute
70
+ vote.create,14,2013-02-13 01:09:00,minute
71
+ vote.create,11,2013-02-13 01:10:00,minute
72
+ vote.create,9,2013-02-13 01:11:00,minute
73
+ vote.create,7,2013-02-13 01:12:00,minute
74
+ vote.create,16,2013-02-13 01:13:00,minute
75
+ vote.create,10,2013-02-13 01:14:00,minute
76
+ vote.create,4,2013-02-13 01:15:00,minute
77
+ vote.create,7,2013-02-13 01:16:00,minute
78
+ vote.create,1,2013-02-13 01:17:00,minute
79
+ vote.create,4,2013-02-13 01:18:00,minute
80
+ vote.create,10,2013-02-13 01:19:00,minute
81
+ vote.create,5,2013-02-13 01:20:00,minute
82
+ vote.create,7,2013-02-13 01:21:00,minute
83
+ vote.create,10,2013-02-13 01:22:00,minute
84
+ vote.create,10,2013-02-13 01:23:00,minute
85
+ vote.create,11,2013-02-13 01:24:00,minute
86
+ vote.create,3,2013-02-13 01:25:00,minute
87
+ vote.create,5,2013-02-13 01:26:00,minute
88
+ vote.create,6,2013-02-13 01:27:00,minute
89
+ vote.create,1,2013-02-13 01:28:00,minute
90
+ vote.create,3,2013-02-13 01:29:00,minute
91
+ vote.create,14,2013-02-13 01:30:00,minute
92
+ vote.create,7,2013-02-13 01:31:00,minute
93
+ vote.create,5,2013-02-13 01:32:00,minute
94
+ vote.create,2,2013-02-13 01:33:00,minute
95
+ vote.create,8,2013-02-13 01:34:00,minute
96
+ vote.create,7,2013-02-13 01:35:00,minute
97
+ vote.create,6,2013-02-13 01:37:00,minute
98
+ vote.create,14,2013-02-13 01:38:00,minute
99
+ vote.create,10,2013-02-13 01:39:00,minute
100
+ vote.create,17,2013-02-13 01:40:00,minute
101
+ vote.create,7,2013-02-13 01:41:00,minute
102
+ vote.create,3,2013-02-13 01:42:00,minute
103
+ vote.create,8,2013-02-13 01:43:00,minute
104
+ vote.create,15,2013-02-13 01:44:00,minute
105
+ vote.create,18,2013-02-13 01:45:00,minute
106
+ vote.create,11,2013-02-13 01:46:00,minute
107
+ vote.create,7,2013-02-13 01:47:00,minute
108
+ vote.create,10,2013-02-13 01:48:00,minute
109
+ vote.create,15,2013-02-13 01:49:00,minute
110
+ vote.create,11,2013-02-13 01:50:00,minute
111
+ vote.create,9,2013-02-13 01:51:00,minute
112
+ vote.create,4,2013-02-13 01:52:00,minute
113
+ vote.create,3,2013-02-13 01:53:00,minute
114
+ vote.create,2,2013-02-13 01:54:00,minute
115
+ vote.create,3,2013-02-13 01:55:00,minute
116
+ vote.create,10,2013-02-13 01:56:00,minute
117
+ vote.create,12,2013-02-13 01:57:00,minute
118
+ vote.create,8,2013-02-13 01:58:00,minute
119
+ vote.create,15,2013-02-13 01:59:00,minute
120
+ vote.create,24,2013-02-13 02:00:00,minute
121
+ vote.create,24,2013-02-13 02:01:00,minute
122
+ vote.create,12,2013-02-13 02:02:00,minute
123
+ vote.create,2,2013-02-13 02:02:00,minute
124
+ vote.create,9,2013-02-13 02:03:00,minute
125
+ vote.create,3,2013-02-13 02:04:00,minute
126
+ vote.create,3,2013-02-13 02:05:00,minute
127
+ vote.create,3,2013-02-13 02:06:00,minute
128
+ vote.create,5,2013-02-13 02:07:00,minute
129
+ vote.create,4,2013-02-13 02:08:00,minute
130
+ vote.create,6,2013-02-13 02:09:00,minute
131
+ vote.create,6,2013-02-13 02:10:00,minute
132
+ vote.create,11,2013-02-13 02:11:00,minute
133
+ vote.create,18,2013-02-13 02:12:00,minute
134
+ vote.create,12,2013-02-13 02:13:00,minute
135
+ vote.create,22,2013-02-13 02:14:00,minute
136
+ vote.create,10,2013-02-13 02:15:00,minute
137
+ vote.create,21,2013-02-13 02:16:00,minute
138
+ vote.create,14,2013-02-13 02:17:00,minute
139
+ vote.create,16,2013-02-13 02:18:00,minute
140
+ vote.create,17,2013-02-13 02:19:00,minute
141
+ vote.create,16,2013-02-13 02:20:00,minute
142
+ vote.create,15,2013-02-13 02:21:00,minute
143
+ vote.create,21,2013-02-13 02:22:00,minute
144
+ vote.create,4,2013-02-13 02:23:00,minute
145
+ vote.create,6,2013-02-13 02:24:00,minute
146
+ vote.create,11,2013-02-13 02:25:00,minute
147
+ vote.create,13,2013-02-13 02:26:00,minute
148
+ vote.create,31,2013-02-13 02:27:00,minute
149
+ vote.create,22,2013-02-13 02:28:00,minute
150
+ vote.create,21,2013-02-13 02:29:00,minute
151
+ vote.create,18,2013-02-13 02:30:00,minute
152
+ vote.create,23,2013-02-13 02:31:00,minute
153
+ vote.create,9,2013-02-13 02:32:00,minute
154
+ vote.create,17,2013-02-13 02:33:00,minute
155
+ vote.create,15,2013-02-13 02:34:00,minute
156
+ vote.create,9,2013-02-13 02:35:00,minute
157
+ vote.create,11,2013-02-13 02:36:00,minute
158
+ vote.create,5,2013-02-13 02:37:00,minute
159
+ vote.create,11,2013-02-13 02:38:00,minute
160
+ vote.create,25,2013-02-13 02:39:00,minute
161
+ vote.create,18,2013-02-13 02:40:00,minute
162
+ vote.create,6,2013-02-13 02:41:00,minute
163
+ vote.create,2,2013-02-13 02:42:00,minute
164
+ vote.create,1,2013-02-13 02:43:00,minute
165
+ vote.create,1,2013-02-13 02:44:00,minute
166
+ vote.create,2,2013-02-13 02:45:00,minute
167
+ vote.create,1,2013-02-13 02:47:00,minute
168
+ vote.create,2,2013-02-13 02:48:00,minute
169
+ vote.create,7,2013-02-13 02:49:00,minute
170
+ vote.create,6,2013-02-13 02:50:00,minute
171
+ vote.create,10,2013-02-13 02:51:00,minute
172
+ vote.create,12,2013-02-13 02:52:00,minute
173
+ vote.create,9,2013-02-13 02:53:00,minute
174
+ vote.create,14,2013-02-13 02:54:00,minute
175
+ vote.create,16,2013-02-13 02:55:00,minute
176
+ vote.create,20,2013-02-13 02:56:00,minute
177
+ vote.create,9,2013-02-13 02:57:00,minute
178
+ vote.create,11,2013-02-13 02:58:00,minute
179
+ vote.create,3,2013-02-13 02:59:00,minute
@@ -5,7 +5,7 @@ module MerryGoRound
5
5
  def test_aggregating_from_redis
6
6
  # Load the fixture. There is 60 minutes of data with 3 keys in each minute
7
7
  Timecop.freeze(Time.at(1360695600).utc) do
8
- redis_fixture('hour')
8
+ redis_fixture('minutes')
9
9
  MerryGoRound.aggregate!
10
10
  MerryGoRound.aggregate!
11
11
  end
@@ -16,12 +16,20 @@ module MerryGoRound
16
16
  # 1 hour * 3 keys
17
17
  assert_equal 3, Aggregation.where(granularity: 'hour').count
18
18
 
19
- # No days since there is only an hour of data
20
- assert_equal 0, Aggregation.where(granularity: 'day').count
21
-
22
19
  # The minute aggregations should belong to an hour one
23
20
  refute_nil Aggregation.where(granularity: 'minute').first.parent_id
24
21
  assert_equal 'hour', Aggregation.where(granularity: 'minute').first.parent.granularity
25
22
  end
23
+
24
+ def test_compound_aggregations
25
+ Timecop.freeze(Time.at(1360792056).utc) do
26
+ csv_fixture('votes')
27
+ MerryGoRound.aggregate!
28
+ assert_equal 3, Aggregation.where(granularity: 'hour').count
29
+
30
+ MerryGoRound.aggregate!
31
+ assert_equal 3, Aggregation.where(granularity: 'hour').count
32
+ end
33
+ end
26
34
  end
27
35
  end
@@ -4,7 +4,7 @@ module MerryGoRound
4
4
  class QueryTest < TestCase
5
5
  def test_execute
6
6
  Timecop.freeze(Time.at(1360695600).utc) do
7
- redis_fixture('hour')
7
+ redis_fixture('minutes')
8
8
  MerryGoRound.aggregate!
9
9
  end
10
10
 
@@ -1,11 +1,13 @@
1
+ require 'csv'
2
+
1
3
  module FixtureMacros
2
- def fixture(name)
4
+ def yml_fixture(name)
3
5
  path = File.expand_path("../../fixtures/#{name}.yml", __FILE__)
4
6
  YAML::load(File.open(path))
5
7
  end
6
8
 
7
9
  def redis_fixture(name)
8
- hash = fixture(name)
10
+ hash = yml_fixture(name)
9
11
  redis = MerryGoRound.redis
10
12
 
11
13
  hash.each do |key, value|
@@ -14,4 +16,11 @@ module FixtureMacros
14
16
  end
15
17
  end
16
18
  end
19
+
20
+ def csv_fixture(name)
21
+ path = File.expand_path("../../fixtures/#{name}.csv", __FILE__)
22
+ CSV.foreach(path) do |row|
23
+ MerryGoRound::Aggregation.create(key: row[0], value: row[1], timestamp: row[2], granularity: row[3])
24
+ end
25
+ end
17
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: merry_go_round
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -120,7 +120,8 @@ files:
120
120
  - lib/rails/generators/merry_go_round/install/templates/add_aggregations.rb
121
121
  - lib/rails/generators/merry_go_round/install/templates/merry_go_round.rake
122
122
  - merry_go_round.gemspec
123
- - test/fixtures/hour.yml
123
+ - test/fixtures/minutes.yml
124
+ - test/fixtures/votes.csv
124
125
  - test/merry_go_round/aggregation_test.rb
125
126
  - test/merry_go_round/aggregator_test.rb
126
127
  - test/merry_go_round/query_test.rb
@@ -152,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
153
  version: '0'
153
154
  segments:
154
155
  - 0
155
- hash: 3985102410336867870
156
+ hash: -2084216448482753946
156
157
  requirements: []
157
158
  rubyforge_project:
158
159
  rubygems_version: 1.8.23
@@ -160,7 +161,8 @@ signing_key:
160
161
  specification_version: 3
161
162
  summary: Simple data-warehousing with Redis and PostgreSQL.
162
163
  test_files:
163
- - test/fixtures/hour.yml
164
+ - test/fixtures/minutes.yml
165
+ - test/fixtures/votes.csv
164
166
  - test/merry_go_round/aggregation_test.rb
165
167
  - test/merry_go_round/aggregator_test.rb
166
168
  - test/merry_go_round/query_test.rb