rhcf-timeseries 1.0.3 → 2.0.0pre
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.
- checksums.yaml +4 -4
- data/lib/rhcf/timeseries/manager.rb +13 -9
- data/lib/rhcf/timeseries/query.rb +15 -6
- data/lib/rhcf/timeseries/redis_strategies.rb +145 -60
- data/lib/rhcf/timeseries/version.rb +1 -1
- data/spec/lib/rhcf/timeseries/manager_spec.rb +67 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60bb46afd3e19f758a6167bcc079283ad7d821d0
|
4
|
+
data.tar.gz: 132cd23eb7fc694f11a3dfd9e5200add5441c295
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 281bef05f4f3d6090d0e915b9c19328906cd9ffd12ab9f2ae530b8543481c116ad6c33f5804603dabbb8db2d17de9674818b7d007e4962df1755a427fc2cacff
|
7
|
+
data.tar.gz: d0e4eef0b658335d3856348e053b219014deb3c16c6022b1d2217b630ba4c7f8a95e73dd13f0136a9e8be98ee91a4dfd32d1d4470a5313df592567a8ab9c280d
|
@@ -50,15 +50,15 @@ module Rhcf
|
|
50
50
|
@connection_to_use || fail("No connection given")
|
51
51
|
end
|
52
52
|
|
53
|
-
def store(
|
53
|
+
def store(evt_path, subject_point_hash, moment = Time.now, descend_subject = true, descend_event = true)
|
54
54
|
resolutions = resolutions_of(moment)
|
55
55
|
|
56
|
-
descend(
|
57
|
-
|
58
|
-
descend(
|
56
|
+
descend(evt_path, descend_event) do |event_path|
|
57
|
+
subject_point_hash.each do |subj_path, point_value|
|
58
|
+
descend(subj_path, descend_subject) do |subject_path|
|
59
59
|
resolutions.each do |res|
|
60
60
|
resolution_name, resolution_value = *res
|
61
|
-
store_point_value(
|
61
|
+
store_point_value(event_path, resolution_name, resolution_value, subject_path, point_value)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -98,8 +98,8 @@ module Rhcf
|
|
98
98
|
@strategy.store_point_value(self, subject_path, resolution_name, resolution_value, point_value, event_path)
|
99
99
|
end
|
100
100
|
|
101
|
-
def find(
|
102
|
-
Rhcf::Timeseries::Query.new(
|
101
|
+
def find(evt_filter, from, to = Time.now, subj_filter = nil)
|
102
|
+
Rhcf::Timeseries::Query.new(evt_filter, from, to, self, subj_filter)
|
103
103
|
end
|
104
104
|
|
105
105
|
def resolution(id)
|
@@ -112,8 +112,12 @@ module Rhcf
|
|
112
112
|
@_resolutions ||= @resolution_ids.map { |id| resolution(id) }
|
113
113
|
end
|
114
114
|
|
115
|
-
def
|
116
|
-
@strategy.
|
115
|
+
def ranking(evt_filter, resolution_id, points_on_range, subj_filter, limit)
|
116
|
+
@strategy.ranking(self, evt_filter, resolution_id, points_on_range, subj_filter, limit)
|
117
|
+
end
|
118
|
+
|
119
|
+
def crunch_values(evt_filter, resolution_id, point, subj_filter)
|
120
|
+
@strategy.crunch_values(self, evt_filter, resolution_id, point, subj_filter)
|
117
121
|
end
|
118
122
|
end
|
119
123
|
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
module Rhcf
|
2
2
|
module Timeseries
|
3
3
|
class Query
|
4
|
-
def initialize(
|
4
|
+
def initialize(evt_filter, from, to, series, subj_filter = nil)
|
5
5
|
from, to = to, from if from > to
|
6
6
|
|
7
7
|
@series = series
|
8
|
-
@
|
8
|
+
@evt_filter = evt_filter
|
9
9
|
@from = from
|
10
10
|
@to = to
|
11
11
|
|
12
|
-
@
|
13
|
-
@limit = limit
|
12
|
+
@subj_filter = subj_filter
|
14
13
|
end
|
15
14
|
|
16
15
|
def total(resolution_id=nil)
|
@@ -25,12 +24,18 @@ module Rhcf
|
|
25
24
|
accumulator
|
26
25
|
end
|
27
26
|
|
27
|
+
def ranking(limit, resolution_id = nil)
|
28
|
+
resolution_id ||= better_resolution[:id]
|
29
|
+
points_on_range = point_range(resolution_id)
|
30
|
+
@series.ranking(@evt_filter, resolution_id, points_on_range, @subj_filter, limit)
|
31
|
+
end
|
32
|
+
|
28
33
|
def points(resolution_id)
|
29
34
|
list =[]
|
30
35
|
|
31
36
|
point_range(resolution_id) do |point|
|
32
37
|
|
33
|
-
values = @series.crunch_values(@
|
38
|
+
values = @series.crunch_values(@evt_filter, resolution_id, point, @subj_filter)
|
34
39
|
|
35
40
|
next if values.empty?
|
36
41
|
data = {moment: point, values: values }
|
@@ -44,14 +49,18 @@ module Rhcf
|
|
44
49
|
end
|
45
50
|
|
46
51
|
def point_range(resolution_id)
|
52
|
+
points_on_range = []
|
47
53
|
resolution = @series.resolution(resolution_id)
|
48
54
|
span = resolution[:span]
|
49
55
|
ptr = @from.dup
|
50
56
|
while ptr < @to
|
51
57
|
point = @series.resolution_value_at(ptr, resolution_id)
|
52
|
-
yield point
|
58
|
+
yield point if block_given?
|
59
|
+
points_on_range << point
|
53
60
|
ptr += span.to_i
|
54
61
|
end
|
62
|
+
|
63
|
+
points_on_range
|
55
64
|
rescue FloatDomainError
|
56
65
|
# OK
|
57
66
|
end
|
@@ -5,16 +5,16 @@ module Rhcf
|
|
5
5
|
'H'
|
6
6
|
end
|
7
7
|
|
8
|
-
def crunch_values(manager,
|
9
|
-
values = hgetall(manager, EVENT_POINT_TOKEN,
|
10
|
-
values.reject!{|event, value| !
|
8
|
+
def crunch_values(manager, evt_filter, resolution_id, time_point, subj_filter)
|
9
|
+
values = hgetall(manager, EVENT_POINT_TOKEN, evt_filter, resolution_id, time_point)
|
10
|
+
values.reject!{|event, value| !subj_filter.match?(event) } if subj_filter
|
11
11
|
values
|
12
12
|
end
|
13
13
|
|
14
|
-
def store_point_value(manager,
|
15
|
-
key =
|
16
|
-
manager.connection_to_use.hincrby(key,
|
17
|
-
manager.connection_to_use.expire(key, DEFAULT_RESOLUTIONS_MAP[
|
14
|
+
def store_point_value(manager, event_path, resolution_id, resolution_val, subject_path, increment)
|
15
|
+
key = point_prefix(manager, event_path, resolution_id, resolution_val)
|
16
|
+
manager.connection_to_use.hincrby(key, subject_path, increment)
|
17
|
+
manager.connection_to_use.expire(key, DEFAULT_RESOLUTIONS_MAP[resolution_id][:ttl])
|
18
18
|
end
|
19
19
|
|
20
20
|
def hgetall(manager, k,s,r,p)
|
@@ -23,30 +23,49 @@ module Rhcf
|
|
23
23
|
hash[_k] = value.to_i
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
def point_prefix(manager, evt_filter, resolution_id, time_point = nil, subj_path = nil)
|
28
|
+
[manager.prefix, EVENT_POINT_TOKEN, evt_filter, resolution_id, time_point, subj_path].compact.join(NAMESPACE_SEPARATOR)
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_prefix(manager, evt_filter, resolution_id, time_point = nil)
|
32
|
+
[manager.prefix, EVENT_SET_TOKEN, evt_filter, resolution_id, time_point].compact.join(NAMESPACE_SEPARATOR)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
26
37
|
end
|
27
38
|
|
28
39
|
class RedisStringBasedStrategy
|
40
|
+
|
41
|
+
def point_prefix(manager, evt_filter, resolution_id, time_point = nil, subj_path = nil)
|
42
|
+
[manager.prefix, EVENT_POINT_TOKEN, evt_filter, resolution_id, time_point, subj_path].compact.join(NAMESPACE_SEPARATOR)
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_prefix(manager, evt_filter, resolution_id, time_point = nil)
|
46
|
+
[manager.prefix, EVENT_SET_TOKEN, evt_filter, resolution_id, time_point].compact.join(NAMESPACE_SEPARATOR)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
29
50
|
def id
|
30
51
|
fail 'AbstractStrategy'
|
31
52
|
end
|
32
53
|
|
33
|
-
def store_point_value(manager,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
manager.connection_to_use.
|
38
|
-
|
54
|
+
def store_point_value(manager, event_path, resolution_name, resolution_val, subj_path, increment)
|
55
|
+
set_key = set_prefix(manager, event_path, resolution_name, resolution_val)
|
56
|
+
counter_key = point_prefix(manager, event_path, resolution_name, resolution_val, subj_path)
|
57
|
+
|
58
|
+
manager.connection_to_use.sadd(set_key, subj_path)
|
59
|
+
manager.connection_to_use.incrby(counter_key, increment)
|
39
60
|
|
40
|
-
|
41
|
-
|
42
|
-
manager.connection_to_use.sadd(key, event_path)
|
43
|
-
manager.connection_to_use.expire(key, DEFAULT_RESOLUTIONS_MAP[resolution_name][:ttl])
|
61
|
+
manager.connection_to_use.expire(counter_key, DEFAULT_RESOLUTIONS_MAP[resolution_name][:ttl])
|
62
|
+
manager.connection_to_use.expire(set_key, DEFAULT_RESOLUTIONS_MAP[resolution_name][:ttl])
|
44
63
|
end
|
45
64
|
|
46
|
-
def events_for_subject_on(manager,
|
47
|
-
key =
|
65
|
+
def events_for_subject_on(manager, evt_filter, res_point, resolution_id, subj_filter)
|
66
|
+
key = set_prefix(manager, evt_filter, resolution_id, res_point)
|
48
67
|
events = manager.connection_to_use.smembers(key)
|
49
|
-
events = events.select{|event|
|
68
|
+
events = events.select{|event| subj_filter.match?(event) } if subj_filter
|
50
69
|
events
|
51
70
|
end
|
52
71
|
end
|
@@ -56,9 +75,9 @@ module Rhcf
|
|
56
75
|
'M'
|
57
76
|
end
|
58
77
|
|
59
|
-
def crunch_values(manager,
|
60
|
-
events = events_for_subject_on(manager,
|
61
|
-
mget(manager, EVENT_POINT_TOKEN,
|
78
|
+
def crunch_values(manager, evt_filter, resolution_id, time_point, subj_filter)
|
79
|
+
events = events_for_subject_on(manager, evt_filter, time_point, resolution_id, subj_filter)
|
80
|
+
mget(manager, EVENT_POINT_TOKEN, evt_filter, resolution_id, time_point, events)
|
62
81
|
end
|
63
82
|
|
64
83
|
def mget(manager, k, s, r, p, es)
|
@@ -76,24 +95,39 @@ module Rhcf
|
|
76
95
|
class RedisMgetLuaStrategy < RedisMgetStrategy
|
77
96
|
def id; 'ME'; end
|
78
97
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
98
|
+
def ranking(manager, evt_filter, resolution_id, points_on_range, subj_filter, limit)
|
99
|
+
point_prefix = point_prefix(manager, evt_filter, resolution_id)
|
100
|
+
set_prefix = set_prefix(manager, evt_filter, resolution_id)
|
101
|
+
|
102
|
+
manager.connection_to_use.evalsha(evalsha_for(manager, :ranking),
|
103
|
+
keys: points_on_range,
|
104
|
+
argv: [
|
105
|
+
evt_filter,
|
106
|
+
subj_filter && subj_filter.to_lua_pattern,
|
107
|
+
set_prefix,
|
108
|
+
point_prefix,
|
109
|
+
limit
|
110
|
+
])
|
111
|
+
end
|
112
|
+
|
113
|
+
def events_for_subject_on(manager, evt_filter, time_point, resolution_id, subj_filter)
|
114
|
+
key = set_prefix(manager, resolution_id, evt_filter, time_point)
|
115
|
+
events = if subj_filter
|
116
|
+
manager.connection_to_use.evalsha(evalsha_for(manager, :smembers_matching),
|
117
|
+
keys: [key], argv: [subj_filter.to_lua_pattern])
|
84
118
|
else
|
85
119
|
manager.connection_to_use.smembers(key)
|
86
120
|
end
|
87
121
|
events
|
88
122
|
end
|
89
123
|
|
90
|
-
def crunch_values(manager,
|
91
|
-
|
92
|
-
|
93
|
-
set_key = [manager.prefix, EVENT_SET_TOKEN, resolution_id, point, subject].join(NAMESPACE_SEPARATOR)
|
124
|
+
def crunch_values(manager, evt_filter, resolution_id, time_point, subj_filter)
|
125
|
+
point_prefix = point_prefix(manager, resolution_id, evt_filter, time_point)
|
126
|
+
set_key = point_prefix(manager, resolution_id, evt_filter, time_point)
|
94
127
|
|
95
|
-
data = manager.connection_to_use.evalsha(evalsha_for(:mget_matching_smembers),
|
96
|
-
keys: [set_key],
|
128
|
+
data = manager.connection_to_use.evalsha(evalsha_for(manager, :mget_matching_smembers),
|
129
|
+
keys: [set_key],
|
130
|
+
argv: [point_prefix, subj_filter && subj_filter.to_lua_pattern])
|
97
131
|
|
98
132
|
return {} if data.nil?
|
99
133
|
result = {}
|
@@ -110,17 +144,63 @@ module Rhcf
|
|
110
144
|
result
|
111
145
|
end
|
112
146
|
|
113
|
-
def evalsha_for(sym_os_lua_script)
|
114
|
-
|
147
|
+
def evalsha_for(manager, sym_os_lua_script)
|
148
|
+
register_lua_scripts(manager.connection_to_use).fetch(sym_os_lua_script)
|
115
149
|
end
|
116
150
|
|
117
|
-
def register_lua_scripts
|
151
|
+
def register_lua_scripts(connection)
|
118
152
|
|
119
153
|
@lua_script_register ||=
|
120
154
|
begin
|
155
|
+
ranking_script = <<-EOF
|
156
|
+
local evt_filter = ARGV[1]
|
157
|
+
local subj_filter = ARGV[2]
|
158
|
+
local set_prefix = ARGV[3]
|
159
|
+
local point_prefix = ARGV[4]
|
160
|
+
local limit = tonumber(ARGV[5])
|
161
|
+
|
162
|
+
local set_keys = {}
|
163
|
+
for _, time in pairs(KEYS) do
|
164
|
+
table.insert(set_keys, set_prefix .. '|' .. time)
|
165
|
+
end
|
166
|
+
|
167
|
+
local all_subjects = redis.call("SUNION", unpack(set_keys))
|
168
|
+
local filtered_subjects = {}
|
169
|
+
|
170
|
+
if subj_filter then
|
171
|
+
for _, val in pairs(all_subjects) do
|
172
|
+
if string.match(val, subj_filter) then
|
173
|
+
table.insert(filtered_subjects, val)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
else
|
177
|
+
filtered_subjects = all_subjects
|
178
|
+
end
|
179
|
+
|
180
|
+
local counter_tuples = {}
|
181
|
+
|
182
|
+
for _, subject in pairs(filtered_subjects) do
|
183
|
+
local my_counter_keys = {}
|
184
|
+
|
185
|
+
for _, time in pairs(KEYS) do
|
186
|
+
table.insert(my_counter_keys, point_prefix .. "|" .. time .. "|" .. subject)
|
187
|
+
end
|
188
|
+
|
189
|
+
local counter_total = 0
|
190
|
+
for _, val in pairs(redis.call("MGET", unpack(my_counter_keys))) do
|
191
|
+
counter_total = counter_total + ( tonumber(val) or 0 )
|
192
|
+
end
|
193
|
+
|
194
|
+
table.insert(counter_tuples, {subject, counter_total} )
|
195
|
+
end
|
196
|
+
|
197
|
+
table.sort(counter_tuples, function(a, b) return b[2] < a[2] end )
|
198
|
+
return counter_tuples
|
199
|
+
EOF
|
200
|
+
|
121
201
|
smembers_matching = <<-EOF
|
122
202
|
local matches = {}
|
123
|
-
for _, val in
|
203
|
+
for _, val in pairs(redis.call('smembers', KEYS[1])) do
|
124
204
|
if string.match(val, ARGV[1]) then
|
125
205
|
table.insert(matches, val)
|
126
206
|
end
|
@@ -136,23 +216,26 @@ module Rhcf
|
|
136
216
|
local keys = {}
|
137
217
|
local keys_to_mget = {}
|
138
218
|
|
219
|
+
|
139
220
|
local function log(msg)
|
140
|
-
|
221
|
+
redis.call('publish', 'log', "XDEBUG: " .. msg)
|
141
222
|
end
|
142
223
|
|
143
224
|
local function mget_in_batches(keys_to_mget)
|
144
|
-
local step
|
145
|
-
local results
|
225
|
+
local step = 1024
|
226
|
+
local results = {}
|
146
227
|
local last_end = 0
|
147
|
-
local partial
|
228
|
+
local partial = {}
|
229
|
+
|
148
230
|
|
149
231
|
local function mget_batch(ini , fin)
|
150
232
|
log("Getting from " .. ini .. ' to ' .. fin .. ' on a total of ' .. #keys_to_mget)
|
233
|
+
|
151
234
|
partial = redis.call('MGET', unpack(keys_to_mget, ini, fin))
|
152
235
|
for _, value in pairs(partial) do table.insert(results, value) end
|
153
236
|
end
|
154
237
|
|
155
|
-
for ending = step,
|
238
|
+
for ending = step, #keys_to_mget, step do
|
156
239
|
mget_batch(last_end + 1, ending)
|
157
240
|
last_end = ending
|
158
241
|
end
|
@@ -166,16 +249,14 @@ module Rhcf
|
|
166
249
|
|
167
250
|
local function sort_and_limit_tuples(subjects, values)
|
168
251
|
local dictionary = {}
|
169
|
-
for i,
|
252
|
+
for i, evt_filter in pairs(subjects) do
|
170
253
|
local value = values[i] or 0
|
171
|
-
|
172
|
-
dictionary[subject] = (dictionary[subject] or 0) + value
|
254
|
+
dictionary[evt_filter] = (dictionary[evt_filter] or 0) + value
|
173
255
|
end
|
174
256
|
|
175
257
|
local tuples = {}
|
176
|
-
for
|
177
|
-
|
178
|
-
table.insert(tuples, { subject, value } )
|
258
|
+
for evt_filter, value in pairs(dictionary) do
|
259
|
+
table.insert(tuples, { evt_filter, value } )
|
179
260
|
end
|
180
261
|
|
181
262
|
table.sort(tuples, function(a, b) return b[2] < a[2] end )
|
@@ -186,16 +267,19 @@ module Rhcf
|
|
186
267
|
for i, tuple in pairs(tuples) do
|
187
268
|
if #new_subjects >= limit then break end
|
188
269
|
|
189
|
-
local
|
270
|
+
local evt_filter = tuple[1]
|
190
271
|
local value = tuple[2]
|
191
272
|
|
192
|
-
table.insert(new_subjects,
|
273
|
+
table.insert(new_subjects, evt_filter)
|
193
274
|
table.insert(new_counts, value)
|
194
275
|
end
|
195
276
|
|
196
277
|
return {new_subjects, new_counts}
|
197
278
|
end
|
198
279
|
|
280
|
+
log("SETKEY " .. set_key ) -- #.. " | KEY prefix: " .. key_prefix .. " FILTER PATTERN: " .. filter_pattern)
|
281
|
+
-- log("SETKEY " .. set_key .. " | KEY prefix: " .. key_prefix .. " FILTER PATTERN: " .. filter_pattern)
|
282
|
+
|
199
283
|
for _, val in ipairs(redis.call('smembers', set_key)) do
|
200
284
|
if (filter_pattern and string.match(val, filter_pattern)) or not filter_pattern then
|
201
285
|
table.insert(keys, val)
|
@@ -205,9 +289,10 @@ module Rhcf
|
|
205
289
|
|
206
290
|
if table.getn(keys) > 0 then
|
207
291
|
local values = mget_in_batches(keys_to_mget)
|
208
|
-
local sorted = sort_and_limit_tuples(keys, values)
|
209
|
-
log ("Values card " .. #values .. " | keys card: " .. #keys)
|
210
|
-
return sorted
|
292
|
+
-- local sorted = sort_and_limit_tuples(keys, values)
|
293
|
+
-- log ("Values card " .. #values .. " | keys card: " .. #keys)
|
294
|
+
-- return sorted
|
295
|
+
return {keys, values}
|
211
296
|
else
|
212
297
|
return {{},{}}
|
213
298
|
end
|
@@ -215,7 +300,8 @@ module Rhcf
|
|
215
300
|
|
216
301
|
{
|
217
302
|
mget_matching_smembers: connection.script(:load, mget_matching_smembers),
|
218
|
-
smembers_matching: connection.script(:load, smembers_matching)
|
303
|
+
smembers_matching: connection.script(:load, smembers_matching),
|
304
|
+
ranking: connection.script(:load, ranking_script)
|
219
305
|
}
|
220
306
|
end
|
221
307
|
end
|
@@ -226,18 +312,17 @@ module Rhcf
|
|
226
312
|
'G'
|
227
313
|
end
|
228
314
|
|
229
|
-
def crunch_values(manager,
|
230
|
-
events = events_for_subject_on(manager,
|
315
|
+
def crunch_values(manager, evt_filter, resolution_id, time_point, subj_filter, limit = 100)
|
316
|
+
events = events_for_subject_on(manager, evt_filter, time_point, resolution_id, subj_filter)
|
231
317
|
values = {}
|
232
318
|
events.each do |event|
|
233
|
-
value = get(manager,
|
319
|
+
value = get(manager, point_prefix(manager, evt_filter, resolution_id, time_point))
|
234
320
|
values[event] = value.to_i
|
235
321
|
end
|
236
322
|
values
|
237
323
|
end
|
238
324
|
|
239
|
-
def get(manager,
|
240
|
-
a_key = [manager.prefix, a_key].flatten.join(NAMESPACE_SEPARATOR)
|
325
|
+
def get(manager, a_key)
|
241
326
|
manager.connection_to_use.get(a_key)
|
242
327
|
end
|
243
328
|
end
|
@@ -5,6 +5,26 @@ require 'rhcf/timeseries/manager'
|
|
5
5
|
require 'benchmark'
|
6
6
|
require 'stackprof'
|
7
7
|
|
8
|
+
|
9
|
+
|
10
|
+
def generate_subjects(n_pages, n_edits)
|
11
|
+
edits = [].tap do |me|
|
12
|
+
1.upto(n_edits) do |i|
|
13
|
+
me << "edit#{i}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
[].tap {|me| n_pages.times { me << [edits.sample,SecureRandom.hex].join('/') } }
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_pageviews(evts_count, subjects, mintime, maxtime)
|
20
|
+
pts = []
|
21
|
+
evts_count.times do
|
22
|
+
time = Time.at(rand( (mintime.to_i)..(maxtime.to_i) ))
|
23
|
+
pts << [ subjects.sample ,time]
|
24
|
+
end
|
25
|
+
pts
|
26
|
+
end
|
27
|
+
|
8
28
|
describe Rhcf::Timeseries::Manager do
|
9
29
|
let(:redis){Redis.new}
|
10
30
|
subject{Rhcf::Timeseries::Manager.new(connection: redis)}
|
@@ -58,6 +78,53 @@ describe Rhcf::Timeseries::Manager do
|
|
58
78
|
end
|
59
79
|
end
|
60
80
|
|
81
|
+
describe 'ranking' do
|
82
|
+
subject do
|
83
|
+
Rhcf::Timeseries::Manager.new(connection: redis,
|
84
|
+
resolutions: [:hour],
|
85
|
+
strategy: Rhcf::Timeseries::RedisMgetLuaStrategy)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:n_evts) { 3000 }
|
89
|
+
let(:n_pages) { 15 }
|
90
|
+
let(:n_edits) { 3 }
|
91
|
+
let(:start_time) { Time.parse('2015-01-01')}
|
92
|
+
let(:end_time) { Time.parse('2015-01-02')}
|
93
|
+
|
94
|
+
let(:subjects){ generate_subjects(n_pages, n_edits) }
|
95
|
+
let(:points) { generate_pageviews(n_evts, subjects, start_time, end_time)}
|
96
|
+
|
97
|
+
before do
|
98
|
+
points.each do |subject_and_time|
|
99
|
+
evt_subject, time = *subject_and_time
|
100
|
+
subject.store('pageview', {evt_subject => 1}, time, false, false)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:query) { subject.find("pageview", start_time, end_time) }
|
105
|
+
|
106
|
+
let(:top10_forca_bruta) {
|
107
|
+
acc = {}
|
108
|
+
points.each do |item|
|
109
|
+
s,_t = * item
|
110
|
+
acc[s] ||=0
|
111
|
+
acc[s] +=1
|
112
|
+
|
113
|
+
end
|
114
|
+
acc.sort_by{|i| i.last}.reverse[0,10]
|
115
|
+
}
|
116
|
+
|
117
|
+
it do
|
118
|
+
expect(points.count).to eq n_evts
|
119
|
+
expect(query.ranking(10).count).to eq 10
|
120
|
+
expect(query.ranking(10)).to eq top10_forca_bruta
|
121
|
+
expect(query.points(:hour).count).to eq 24
|
122
|
+
expect(redis.keys('*').count).to eq 24 + 24 * n_pages # ao infinito
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
|
61
128
|
describe "find and total" do
|
62
129
|
let(:start_time){ Time.parse("2000-01-01 00:00:00") }
|
63
130
|
before do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhcf-timeseries
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Romeu Fonseca
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -172,9 +172,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
172
|
version: '0'
|
173
173
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
174
|
requirements:
|
175
|
-
- - "
|
175
|
+
- - ">"
|
176
176
|
- !ruby/object:Gem::Version
|
177
|
-
version:
|
177
|
+
version: 1.3.1
|
178
178
|
requirements: []
|
179
179
|
rubyforge_project:
|
180
180
|
rubygems_version: 2.2.2
|