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.
- data/lib/merry_go_round/aggregator.rb +49 -25
- data/lib/merry_go_round/version.rb +1 -1
- data/test/fixtures/{hour.yml → minutes.yml} +0 -0
- data/test/fixtures/votes.csv +179 -0
- data/test/merry_go_round/aggregator_test.rb +12 -4
- data/test/merry_go_round/query_test.rb +1 -1
- data/test/support/fixtures.rb +11 -2
- metadata +6 -4
@@ -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
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
73
|
-
|
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
|
-
|
76
|
-
|
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
|
-
|
80
|
-
|
84
|
+
# Get the aggregated value
|
85
|
+
# TODO: This should probably done in SQL
|
86
|
+
value = children.collect(&:value).reduce(:+)
|
81
87
|
|
82
|
-
|
83
|
-
|
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
|
-
|
89
|
-
|
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
|
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('
|
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
|
data/test/support/fixtures.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
1
3
|
module FixtureMacros
|
2
|
-
def
|
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 =
|
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.
|
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/
|
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:
|
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/
|
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
|