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.

Parameters:

  • name (String)

    The timeseries name.

  • options (Hash) (defaults to: {})

    The options hash.

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.



24
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
# File 'lib/time_series.rb', line 24

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 :second
        @resolution = :second
  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.



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

def duration
  @duration
end

#nameObject (readonly)

Returns the value of attribute name.



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

def name
  @name
end

#resolutionObject (readonly)

Returns the value of attribute resolution.



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

def resolution
  @resolution
end

Instance Method Details

#allHash

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

Returns:

  • (Hash)

    contents of all the keys



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

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

Parameters:

  • array (Array)

    Array of Keys

  • Number (Integer)

    of seconds that a key is considered recent

Returns:

  • (Array)

    The new array



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

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

#clearObject

Deletes all the keys

Returns:

  • Number of keys deleted



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

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.

Parameters:

  • keys (Array)

    to be compressed

Returns:

  • (Integer)

    Number of keys compressed



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

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

Returns:



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

def current_key
  time_to_key current_time, @resolution
end

#current_timeTime

Returns the current time.

Returns:

  • (Time)

    the current time



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

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



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

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

#days(*time) ⇒ Array

Keys with day resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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



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

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

#hours(*time) ⇒ Array

Keys with hour resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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

Returns:

  • (Array)

    all the keys in a String Array



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

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

#lastHash

Returns the contents of the last key

Returns:

  • (Hash)

    contents of the last key



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

def last
  last_key.get
end

#last_keyString

Returns the last key

Returns:



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

def last_key
  time_to_key last_time, @resolution
end

#last_timeTime

Returns the time of the last key.

Returns:

  • (Time)

    the last key’s time



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

def last_time
  current_time - @duration
end

#minute(time) ⇒ Object



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

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

#minutes(*time) ⇒ Array

Keys with minute resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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



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

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

#months(*time) ⇒ Array

Keys with month resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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

Returns:

  • (Hash)

    contents of the previous key



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

def previous
  previous_key.get
end

#previous_keyString

Returns the previous key

Returns:



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

def previous_key
 time_to_key previous_time, @resolution
end

#previous_timeTime

Returns the time of the previous key.

Returns:

  • (Time)

    the previous key’s time



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

def previous_time
  current_time - 2 * @duration
end

#push(term) ⇒ Object

Push a new Term into the Timeseries



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

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

#remove_by_score(keys, *population) ⇒ Array

Remove terms with low scores

Parameters:

  • keys (Array)

    that will be examined

Returns:

  • (Array)

    Number of keys the operation took place, it doesn’t mean that something changed



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

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



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

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

#seconds(*time) ⇒ Array

Keys with second resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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

Parameters:

  • time (Time)

    The Time

  • [String] (Hash)

    a customizable set of options

Returns:



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

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



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

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

#years(*time) ⇒ Array

Keys with year resolution

Parameters:

  • time (Array)

Returns:

  • (Array)

    Array with the keys



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

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