Skip to content

Instantly share code, notes, and snippets.

@marianposaceanu
Forked from cpatni/app.rb
Created March 6, 2012 09:42
Show Gist options
  • Save marianposaceanu/1985344 to your computer and use it in GitHub Desktop.
Save marianposaceanu/1985344 to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment