merry_go_round 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|