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