Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
unique calculation using redis
require 'sinatra'
require 'redis'
require 'json'
require 'date'
class String
def &(str)
result = ''
result.force_encoding("BINARY")
min = [self.length, str.length].min
(0...min).each do |i|
result << (self[i].ord & str[i].ord)
end
result
end
def |(str)
result = ''
result.force_encoding("BINARY")
min = [self.length, str.length].min
(0...min).each do |i|
result << (self[i].ord | str[i].ord)
end
if self.length > str.length
result << self[min ... self.length]
elsif self.length < str.length
result << str[min ... str.length]
end
result
end
def population_count
count = 0
(0 ... self.length).each do |i|
count += _population_count_byte(self[i].ord)
end
count
end
private
ONE_BITS = [0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4]
#It works with 8 bits
def _population_count_byte(x)
count = 0
count = ONE_BITS[x&0x0f]
count += ONE_BITS[x>>4]
count
end
end
helpers do
def redis
$redis ||= Redis.new
end
def unique_count(event, from, to)
uniques = ''
(from..to).each do |date|
key = "#{event}.#{date.strftime('%y%m%d')}"
bitmap = redis.get(key)
if bitmap
bitmap.force_encoding("BINARY")
uniques |= bitmap
end
end
uniques.population_count
end
end
get '/collect/:event/for/:user_id/on/:date' do |event,user_id,date|
time = Date.parse(date)
key = "#{event}.#{time.strftime('%y%m%d')}"
if redis.setbit(key, user_id, 1)
204
else
500
end
end
get '/unique/:event/in/last/:n/days?' do |event,n|
content_type :json
to = Date.today
from = to - n.to_i
{:from => from, :to => to, :unique_count => unique_count(event,from,to)}.to_json
end
@makevoid
Copy link

makevoid commented Jan 14, 2012

Thanks for the code example, It's great!
I link the post for reference: http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment