rhcf-timeseries 1.0.3 → 2.0.0pre

Sign up to get free protection for your applications and to get access to all the features.
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