lib/picky/backends/redis.rb in picky-4.0.0pre1 vs lib/picky/backends/redis.rb in picky-4.0.0pre2

- old
+ new

@@ -10,44 +10,60 @@ :immediate def initialize options = {} super options - require 'redis' + maybe_load_hiredis + check_hiredis_gem + check_redis_gem + @client = options[:client] || ::Redis.new(:db => (options[:db] || 15)) @immediate = options[:immediate] + end + def maybe_load_hiredis + require 'hiredis' + rescue LoadError + # It's ok. + end + def check_hiredis_gem + require 'redis/connection/hiredis' + rescue LoadError + # It's ok, the next check will fail if this one does. + end + def check_redis_gem + require 'redis' rescue LoadError => e warn_gem_missing 'redis', 'the Redis client' end # Returns an object that on #initial, #load returns an object that responds to: # [:token] # => [id, id, id, id, id] (an array of ids) # def create_inverted bundle extract_lambda_or(inverted, bundle, client) || - List.new(client, "#{bundle.identifier}:inverted", immediate: immediate) + List.new(client, "#{PICKY_ENVIRONMENT}:#{bundle.identifier}:inverted", immediate: immediate) end # Returns an object that on #initial, #load returns an object that responds to: # [:token] # => 1.23 (a weight) # def create_weights bundle extract_lambda_or(weights, bundle, client) || - Float.new(client, "#{bundle.identifier}:weights", immediate: immediate) + Float.new(client, "#{PICKY_ENVIRONMENT}:#{bundle.identifier}:weights", immediate: immediate) end # Returns an object that on #initial, #load returns an object that responds to: # [:encoded] # => [:original, :original] (an array of original symbols this similarity encoded thing maps to) # def create_similarity bundle extract_lambda_or(similarity, bundle, client) || - List.new(client, "#{bundle.identifier}:similarity", immediate: immediate) + List.new(client, "#{PICKY_ENVIRONMENT}:#{bundle.identifier}:similarity", immediate: immediate) end # Returns an object that on #initial, #load returns an object that responds to: # [:key] # => value (a value for this config key) # def create_configuration bundle extract_lambda_or(configuration, bundle, client) || - String.new(client, "#{bundle.identifier}:configuration", immediate: immediate) + String.new(client, "#{PICKY_ENVIRONMENT}:#{bundle.identifier}:configuration", immediate: immediate) end # Returns an object that on #initial, #load returns an object that responds to: # [id] # => [:sym1, :sym2] # def create_realtime bundle @@ -87,35 +103,80 @@ infos = client.info version_string = infos['redis_version'] || infos[:redis_version] version_string.split('.').map &:to_i end + # Returns the total weight for the combinations. + # + def weight combinations + # Note: A nice experiment that generated far too many strings. + # + # if redis_with_scripting? + # @@weight_script = "local sum = 0; for i=1,#(KEYS),2 do local value = redis.call('hget', KEYS[i], KEYS[i+1]); if value then sum = sum + value end end return sum;" + # + # require 'digest/sha1' + # @@weight_sent_once = nil + # + # # Scripting version of #ids. + # # + # class << self + # def weight combinations + # namespaces_keys = combinations.inject([]) do |namespaces_keys, combination| + # namespaces_keys << "#{combination.bundle.identifier}:weights" + # namespaces_keys << combination.token.text + # end + # + # # Assume it's using EVALSHA. + # # + # begin + # client.evalsha @@weight_sent_once, + # namespaces_keys.size, + # *namespaces_keys + # rescue RuntimeError => e + # # Make the server have a SHA-1 for the script. + # # + # @@weight_sent_once = Digest::SHA1.hexdigest @@weight_script + # client.eval @@weight_script, + # namespaces_keys.size, + # *namespaces_keys + # end + # end + # end + # else + # class << self + # def weight combinations + combinations.score + # end + # end + # end + # # Call the newly installed version. + # # + # weight combinations + end + # Returns the result ids for the allocation. # # Developers wanting to program fast intersection # routines, can do so analogue to this in their own # backend implementations. # # Note: We use the amount and offset hints to speed Redis up. # - # TODO What if it hasn't been dumped? - # Move this method to the actual backends? - # def ids combinations, amount, offset # TODO FIXME This is actually not correct: # A dumped/loaded Redis backend should use # the Redis backend calculation method. # So loaded? would be more appropriate. # if immediate # Just checked once on the first call. # if redis_with_scripting? - @@script = "local intersected = redis.call('zinterstore', ARGV[1], #(KEYS), unpack(KEYS)); if intersected == 0 then redis.call('del', ARGV[1]); return {}; end local results = redis.call('zrange', ARGV[1], tonumber(ARGV[2]), tonumber(ARGV[3])); redis.call('del', ARGV[1]); return results;" + @@ids_script = "local intersected = redis.call('zinterstore', ARGV[1], #(KEYS), unpack(KEYS)); if intersected == 0 then redis.call('del', ARGV[1]); return {}; end local results = redis.call('zrange', ARGV[1], tonumber(ARGV[2]), tonumber(ARGV[3])); redis.call('del', ARGV[1]); return results;" require 'digest/sha1' - @@sent_once = nil + @@ids_sent_once = nil # Scripting version of #ids. # class << self def ids combinations, amount, offset @@ -124,21 +185,21 @@ end # Assume it's using EVALSHA. # begin - client.evalsha @@sent_once, + client.evalsha @@ids_sent_once, identifiers.size, *identifiers, generate_intermediate_result_id, offset, (offset + amount) rescue RuntimeError => e # Make the server have a SHA-1 for the script. # - @@sent_once = Digest::SHA1.hexdigest @@script - client.eval @@script, + @@ids_sent_once = Digest::SHA1.hexdigest @@ids_script + client.eval @@ids_script, identifiers.size, *identifiers, generate_intermediate_result_id, offset, (offset + amount) @@ -189,11 +250,9 @@ results end end end else - # TODO Refactor! - # class << self def ids combinations, _, _ # Get the ids for each combination. # id_arrays = combinations.inject([]) do |total, combination| \ No newline at end of file