diff --git a/redis-timeseries-sorted-set.rb b/redis-timeseries-sorted-set.rb new file mode 100644 index 0000000..f251ba4 --- /dev/null +++ b/redis-timeseries-sorted-set.rb @@ -0,0 +1,42 @@ +require 'base64' + +class RedisTimeSeries + def initialize(prefix,timestep,redis) + @prefix = prefix + @timestep = timestep + @redis = redis + end + + def normalize_time(t) + t = t.to_i + t - (t % @timestep) + end + + def getkey(t) + "ts:#{@prefix}:#{normalize_time t}" + end + + def add(data,timestamp=nil,marshal=true) + timestamp ||= Time.now.to_f + data = marshal ? Marshal.dump(data) : data + @redis.zadd(getkey(timestamp), timestamp, data) + end + + def fetch_range(begin_time,end_time,marshal=true) + begin_time = begin_time.to_f + end_time = end_time.to_f + result = (0..((end_time - begin_time) / @timestep)).collect do |i| + key = getkey(begin_time + (i*@timestep)) + + r = @redis.zrangebyscore(key, begin_time.to_f,end_time.to_f) + marshal ? r.collect{|elem| Marshal.load(elem) } : r + end + result.flatten + end + + def fetch_timestep(time, marshal=true) + t = time.to_f + r = @redis.zrangebyscore(getkey(time), t, t) + marshal ? r.collect{|elem| Marshal.load(elem) } : r + end +end diff --git a/sorted-set-example.rb b/sorted-set-example.rb new file mode 100644 index 0000000..537d6d9 --- /dev/null +++ b/sorted-set-example.rb @@ -0,0 +1,33 @@ +require 'rubygems' +require 'redis' +require './redis-timeseries-sorted-set' + +# To show the lib implementation here we use a timestep of just one second. +# Then we sample every 0.1 seconds, producing on average 10 samples per key. +# This way we should how multi-key range queries are working. +ts = RedisTimeSeries.new("test",1,Redis.new) + +now = Time.now.to_f +puts "Adding data points: " +(0..300).each{|i| + print "#{i} " + STDOUT.flush + time = (now+(i/10.0)) + ts.add({:time => time, :data => i.to_s}, time) +} +puts "" + +# Get the second in the middle of our sampling. +begin_time = now+1 +end_time = now+2 +puts "\nGet range from #{begin_time} to #{end_time}" + +ts.fetch_range(begin_time,end_time).each{|record| + puts "Record time #{record[:time]}, data #{record[:data]}" +} + +# Show API to get a single timestep +puts "\nGet a single timestep near #{begin_time}" +ts.fetch_timestep(begin_time).each{|record| + puts "Record time #{record[:time]}, data #{record[:data]}" +}