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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 43ad07821290e60cc41c8741c44ef2f2e5b7769d
4
- data.tar.gz: dae3053f370a61499301acfe5b841156ace2bc3a
3
+ metadata.gz: 60bb46afd3e19f758a6167bcc079283ad7d821d0
4
+ data.tar.gz: 132cd23eb7fc694f11a3dfd9e5200add5441c295
5
5
  SHA512:
6
- metadata.gz: 42b5890b40e7084f54987deac6f52050c65bd01191edc2730346703962489e41468b93700113d96d7f219995374cde592c49957b56a1c22d2d40dfcb6087eea6
7
- data.tar.gz: 2671b695bd0edb1d1b8e077d77dde591b3d16f31455c7315024fd0f9495740f2a54bf7e58202f381996d72693d84fb820f4facfea72e0d0dc6f50c817885c766
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(subject, event_point_hash, moment = Time.now, descend_subject = true, descend_event = true)
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(subject, descend_subject) do |subject_path|
57
- event_point_hash.each do |event, point_value|
58
- descend(event, descend_event) do |event_path|
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(subject_path, resolution_name, resolution_value, point_value, event_path)
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(subject, from, to = Time.now, filter = nil, limit = 1000)
102
- Rhcf::Timeseries::Query.new(subject, from, to, self, filter, limit)
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 crunch_values(subject, resolution_id, point, filter, limit = 1000)
116
- @strategy.crunch_values(self, subject, resolution_id, point, filter, limit)
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(subject, from, to, series, filter = nil, limit = 1000)
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
- @subject = subject
8
+ @evt_filter = evt_filter
9
9
  @from = from
10
10
  @to = to
11
11
 
12
- @filter = filter
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(@subject, resolution_id, point, @filter, @limit)
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, subject, resolution_id, point, filter, limit = 100)
9
- values = hgetall(manager, EVENT_POINT_TOKEN, subject, resolution_id, point)
10
- values.reject!{|event, value| !filter.match?(event) } if filter
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, subject_path, resolution_name, resolution_value, point_value, event_path)
15
- key = [manager.prefix, EVENT_POINT_TOKEN ,subject_path, resolution_name, resolution_value].join(NAMESPACE_SEPARATOR)
16
- manager.connection_to_use.hincrby(key, event_path, point_value)
17
- manager.connection_to_use.expire(key, DEFAULT_RESOLUTIONS_MAP[resolution_name][:ttl])
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, subject_path, resolution_name, resolution_value, point_value, event_path)
34
- store_point_event(manager, resolution_name, resolution_value, subject_path, event_path)
35
- key = [manager.prefix, EVENT_POINT_TOKEN ,subject_path, resolution_name, resolution_value, event_path].join(NAMESPACE_SEPARATOR)
36
- manager.connection_to_use.incrby(key, point_value)
37
- manager.connection_to_use.expire(key, DEFAULT_RESOLUTIONS_MAP[resolution_name][:ttl])
38
- end
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
- def store_point_event(manager, resolution_name, resolution_value, subject_path, event_path)
41
- key = [manager.prefix, EVENT_SET_TOKEN, resolution_name, resolution_value, subject_path].join(NAMESPACE_SEPARATOR)
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, subject, point, resolution_id, filter)
47
- key = [manager.prefix, EVENT_SET_TOKEN, resolution_id, point, subject].join(NAMESPACE_SEPARATOR)
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| filter.match?(event) } if filter
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, subject, resolution_id, point, filter, limit = 100)
60
- events = events_for_subject_on(manager, subject, point, resolution_id, filter)
61
- mget(manager, EVENT_POINT_TOKEN, subject, resolution_id, point, events)
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 events_for_subject_on(manager, subject, point, resolution_id, filter)
80
- key = [manager.prefix, EVENT_SET_TOKEN, resolution_id, point, subject].join(NAMESPACE_SEPARATOR)
81
- events = if filter
82
- manager.connection_to_use.evalsha(evalsha_for(:smembers_matching),
83
- keys: [key], argv: [filter.to_lua_pattern])
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, subject, resolution_id, point, filter, limit = 1000)
91
- register_lua_scripts!(manager.connection_to_use)
92
- point_prefix = [manager.prefix, EVENT_POINT_TOKEN, subject, resolution_id, point].join(NAMESPACE_SEPARATOR)
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], argv: [point_prefix, filter && filter.to_lua_pattern, limit])
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
- @lua_script_register[sym_os_lua_script] || fail("Script for '#{sym_os_lua_script}' not registered")
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!(connection)
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 ipairs(redis.call('smembers', KEYS[1])) do
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
- -- redis.call('publish', 'log', msg)
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 = 1024
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, #keys_to_mget, step do
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, subject in pairs(subjects) do
252
+ for i, evt_filter in pairs(subjects) do
170
253
  local value = values[i] or 0
171
- -- redis.call('publish', 'log', subject .. ' += ' .. value)
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 subject, value in pairs(dictionary) do
177
- -- redis.call('publish', 'log', subject .. ' = ' .. value)
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 subject = tuple[1]
270
+ local evt_filter = tuple[1]
190
271
  local value = tuple[2]
191
272
 
192
- table.insert(new_subjects, subject)
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, subject, resolution_id, point, filter, limit = 100)
230
- events = events_for_subject_on(manager, subject, point, resolution_id, filter)
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, EVENT_POINT_TOKEN, subject, resolution_id, point, event)
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, *a_key)
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
@@ -1,5 +1,5 @@
1
1
  module Rhcf
2
2
  module Timeseries
3
- VERSION = "1.0.3"
3
+ VERSION = "2.0.0pre"
4
4
  end
5
5
  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: 1.0.3
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-08 00:00:00.000000000 Z
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: '0'
177
+ version: 1.3.1
178
178
  requirements: []
179
179
  rubyforge_project:
180
180
  rubygems_version: 2.2.2