Class: TimeSeries

Inherits:
RedisConnection show all
Defined in:
lib/time_series.rb

Overview

TimeSeries Class

Instance Attribute Summary collapse

Attributes inherited from RedisConnection

#redis

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) ⇒ TimeSeries

Create Timeseries.

Options Hash (options):

  • :resolution (String)

    The time resolution: :year, :month, :day, :hour, :minute, :second

  • :duration (Integer)

    Duration is under development. It will allow for example 10, 20 or 30 seconds keys. Now only keys with :minute resolution are available.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/time_series.rb', line 25

def initialize name, options={}
  super # initialize RedisConnection
  
  @name = name
  @prefix="#{$app_prefix}:ts:#{@name}:"
  
  # parse the resolution option
  if options.has_key? :resolution
    @resolution = options[:resolution]
    resolutions = [:year, :month, :day, :hour, :minute, :second]
    #if the resolution option is invalid raise an exception
    unless resolutions.include?(@resolution) #or @resolution.is_a?(Integer)
      raise ArgumentError.new("resolution can be either :year or :month or :day or :hour or :minute or :second")
    end  
  elsif keys.empty? # default resolution is :minute
        @resolution = :minute
  else # try to guess resolution from existing keys
    max_res = 0
    keys.each do |k|
      res = k.count(':')
      max_res = res if res > max_res
    end
    
    case max_res
      when 8 then @resolution = :second
      when 7 then @resolution = :minute
      when 6 then @resolution = :hour
      when 5 then @resolution = :day
      when 4 then @resolution = :month
      when 3 then @resolution = :year
      else raise ArgumentError.new("Cannot guess resolution from existing keys")
    end #case
  end # if
  
  # define the @duration based on @resolution
  case @resolution
    when :year   then @duration = 12*30*24*3600
    when :month  then @duration = 30*24*3600
    when :day    then @duration = 24*3600
    when :hour   then @duration = 3600
    when :minute then @duration = 60
    when :second then @duration = options[:duration] ||= 20
  end
end

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



16
17
18
# File 'lib/time_series.rb', line 16

def duration
  @duration
end

#nameObject (readonly)

Returns the value of attribute name.



16
17
18
# File 'lib/time_series.rb', line 16

def name
  @name
end

#resolutionObject (readonly)

Returns the value of attribute resolution.



16
17
18
# File 'lib/time_series.rb', line 16

def resolution
  @resolution
end

Instance Method Details

#allHash

Returns the contents of all the keys TODO Considering to remove this method



137
138
139
140
141
# File 'lib/time_series.rb', line 137

def all
  all = Hash.new
  keys.each{ |k| all[k.gsub(/#{@prefix}/,'')]=k.get}
  return all
end

#array_older_than(array, time) ⇒ Array

Removes recent keys from a key array



190
191
192
# File 'lib/time_series.rb', line 190

def array_older_than array, time
  array.keep_if { |k| k.time <= Time.now - time }
end

#clearObject

Deletes all the keys



127
128
129
130
131
# File 'lib/time_series.rb', line 127

def clear
  i = 0
  keys.each{|k| @redis.del k; i+=1}
  return i 
end

#compress(keys) ⇒ Integer

Compress keys Key compression merges the given keys of the same resolution to keys of greater resolution. For example seconds are merged into minutes and days are merged into months. The values of the keys are merged too. After the merge the keys are deleted.



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/time_series.rb', line 289

def compress keys
  parents = []
  keys.each do |key|
    unless key.recent? or key.year?
      parent = key.parent
      parents << parent unless parents.include? parent
    end
  end
  
  i = 0
  parents.each do |parent|
    unless parent.recent?
      children = parent.persistant_children
      @redis.zunionstore parent, children
      children.each{|k| @redis.del k; i+=1}
    end
  end
  return i 
end

#current_keyString

Returns the current key



99
100
101
# File 'lib/time_series.rb', line 99

def current_key
  time_to_key current_time, @resolution
end

#current_timeTime

Returns the current time.



73
74
75
76
77
78
79
80
# File 'lib/time_series.rb', line 73

def current_time
  time=Time.at(Time.now.to_i) # this way nsec and usec is 0
  if @resolution == :second
    sec = time.strftime("%S").to_i % @duration
    time = time - sec
  end  
  return time
end

#day(time) ⇒ Object



333
# File 'lib/time_series.rb', line 333

def day time;    time_to_key(time, :day).get end

#days(*time) ⇒ Array

Keys with day resolution



240
241
242
243
244
245
246
247
248
# File 'lib/time_series.rb', line 240

def days *time
  array = keys.keep_if { |k| k.day? and k.persistant?}
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end    
end

#hour(time) ⇒ Object



334
# File 'lib/time_series.rb', line 334

def hour time;   time_to_key(time, :hour).get end

#hours(*time) ⇒ Array

Keys with hour resolution



226
227
228
229
230
231
232
233
234
# File 'lib/time_series.rb', line 226

def hours *time
  array = keys.keep_if { |k| k.hour? and k.persistant?}
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end    
end

#keysArray

Returns all the keys



120
121
122
# File 'lib/time_series.rb', line 120

def keys
  return @redis.keys"#{$app_prefix}:ts:#{@name}:*"
end

#lastHash

Returns the contents of the last key



146
147
148
# File 'lib/time_series.rb', line 146

def last
  last_key.get
end

#last_keyString

Returns the last key



106
107
108
# File 'lib/time_series.rb', line 106

def last_key
  time_to_key last_time, @resolution
end

#last_timeTime

Returns the time of the last key.



85
86
87
# File 'lib/time_series.rb', line 85

def last_time
  current_time - @duration
end

#minute(time) ⇒ Object



335
# File 'lib/time_series.rb', line 335

def minute time; time_to_key(time, :minute).get end

#minutes(*time) ⇒ Array

Keys with minute resolution



212
213
214
215
216
217
218
219
220
# File 'lib/time_series.rb', line 212

def minutes *time
  array = keys.keep_if { |k| k.minute? and k.persistant?}
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end    
end

#month(time) ⇒ Object



332
# File 'lib/time_series.rb', line 332

def month time;  time_to_key(time, :month).get end

#months(*time) ⇒ Array

Keys with month resolution



254
255
256
257
258
259
260
261
262
263
# File 'lib/time_series.rb', line 254

def months *time
  array = keys.keep_if { |k| k.month? and k.persistant?}  
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end  

end

#previousHash

Returns the contents of the previous key



153
154
155
# File 'lib/time_series.rb', line 153

def previous
  previous_key.get
end

#previous_keyString

Returns the previous key



113
114
115
# File 'lib/time_series.rb', line 113

def previous_key
 time_to_key previous_time, @resolution
end

#previous_timeTime

Returns the time of the previous key.



92
93
94
# File 'lib/time_series.rb', line 92

def previous_time
  current_time - 2 * @duration
end

#push(term) ⇒ Object

Push a new Term into the Timeseries



158
159
160
# File 'lib/time_series.rb', line 158

def push term
  @redis.zincrby current_key, 1, term
end

#remove_by_score(keys, *population) ⇒ Array

Remove terms with low scores



313
314
315
316
317
318
319
320
321
322
# File 'lib/time_series.rb', line 313

def remove_by_score keys, *population
  if population.empty?
    population = 1
  else
    population = population.first
  end
  i = 0    
  keys.each {|k| @redis.zremrangebyscore(k, '-inf', population); i+=1} # TODO What zremrangebyscore returns?
  return i     
end

#second(time) ⇒ Object



336
# File 'lib/time_series.rb', line 336

def second time; time_to_key(time, :second).get end

#seconds(*time) ⇒ Array

Keys with second resolution



198
199
200
201
202
203
204
205
206
# File 'lib/time_series.rb', line 198

def seconds *time
  array = keys.keep_if { |k| k.second? and k.persistant?}
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end
end

#time_to_key(time, *resolution) ⇒ String

Convert a Time object to the respective Key TODO Refactoring



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/time_series.rb', line 168

def time_to_key time, *resolution
  if resolution.empty?
    return time.strftime("#{@prefix}%Y:%m:%d:%H:%M:%S")
  else
    resolution = resolution.first
    case resolution
      when :year   then return time.strftime("#{@prefix}%Y")
      when :month  then return time.strftime("#{@prefix}%Y:%m")
      when :day    then return time.strftime("#{@prefix}%Y:%m:%d")
      when :hour   then return time.strftime("#{@prefix}%Y:%m:%d:%H")
      when :minute then return time.strftime("#{@prefix}%Y:%m:%d:%H:%M")
      when :second then return time.strftime("#{@prefix}%Y:%m:%d:%H:%M:%S")
      else puts red "wrong resolution in time_to_key"
    end
  end
end

#year(time) ⇒ Object

def term_weights terms, factor

terms.each do |term, value|
  terms[term]=value*factor
end
return terms

end



331
# File 'lib/time_series.rb', line 331

def year time;   time_to_key(time, :year).get end

#years(*time) ⇒ Array

Keys with year resolution



269
270
271
272
273
274
275
276
277
278
# File 'lib/time_series.rb', line 269

def years *time
  array = keys.keep_if { |k| k.year? and k.persistant?}  
  if time.empty?
    return array
  else
    time = time.first
    return array_older_than array, time
  end  

end