lib/picky/query/base.rb in picky-1.4.1 vs lib/picky/query/base.rb in picky-1.4.2
- old
+ new
@@ -12,39 +12,70 @@
# There are two flavors of queries:
# * Query::Full (Full results with all infos)
# * Query::Live (Same as the Full results without result ids. Useful for query result counters.)
#
module Query
-
+
# The base query class.
#
# Not directly instantiated. However, its methods are used by its subclasses, Full and Live.
#
class Base
-
+
include Helpers::Measuring
-
+
attr_writer :tokenizer, :identifiers_to_remove
attr_accessor :reduce_to_amount, :weights
-
+
# Takes:
# * A number of indexes
# * Options hash (optional) with:
- # * weigher: A weigher. Query::Weigher by default.
# * tokenizer: Tokenizers::Query.default by default.
# * weights: A hash of weights, or a Query::Weights object.
#
- def initialize *index_type_definitions
- options = Hash === index_type_definitions.last ? index_type_definitions.pop : {}
- indexes = index_type_definitions.map &:indexed
-
- @weigher = options[:weigher] || Weigher.new(indexes)
- @tokenizer = options[:tokenizer] || Tokenizers::Query.default
+ def initialize *index_definitions
+ options = Hash === index_definitions.last ? index_definitions.pop : {}
+
+ @indexes = Internals::Query::Indexes.new *index_definitions, combinations_type_for(index_definitions)
+ @tokenizer = options[:tokenizer] || Internals::Tokenizers::Query.default
weights = options[:weights] || Weights.new
@weights = Hash === weights ? Weights.new(weights) : weights
end
+ # Returns the right combinations strategy for
+ # a number of query indexes.
+ #
+ # Currently it isn't possible using Memory and Redis etc.
+ # indexes in the same query index group.
+ #
+ # Picky will raise a Query::Indexes::DifferentTypesError.
+ #
+ @@mapping = {
+ Index::Memory => Internals::Query::Combinations::Memory,
+ Index::Redis => Internals::Query::Combinations::Redis
+ }
+ def combinations_type_for index_definitions_ary
+ index_types = index_definitions_ary.map(&:class)
+ index_types.uniq!
+ raise_different(index_types) if index_types.size > 1
+ !index_types.empty? && @@mapping[*index_types] || Internals::Query::Combinations::Memory
+ end
+ # Currently it isn't possible using Memory and Redis etc.
+ # indexes in the same query index group.
+ #
+ class DifferentTypesError < StandardError
+ def initialize types
+ @types = types
+ end
+ def to_s
+ "Currently it isn't possible to mix #{@types.join(" and ")} Indexes in the same Query."
+ end
+ end
+ def raise_different index_types
+ raise DifferentTypesError.new(index_types)
+ end
+
# This is the main entry point for a query.
# Use this in specs and also for running queries.
#
# Parameters:
# * text: The search text.
@@ -53,52 +84,52 @@
# Note: The Rack adapter calls this method after unravelling the HTTP request.
#
def search_with_text text, offset = 0
search tokenized(text), offset
end
-
+
# Runs the actual search using Query::Tokens.
#
# Note: Internal method, use #search_with_text.
#
def search tokens, offset = 0
results = nil
-
+
duration = timed do
results = execute(tokens, offset) || empty_results(offset) # TODO Does not work yet
end
results.duration = duration.round 6
-
+
results
end
-
+
# Execute a search using Query::Tokens.
#
# Note: Internal method, use #search_with_text.
#
def execute tokens, offset
result_type.from offset, sorted_allocations(tokens)
end
-
+
# Returns an empty result with default values.
#
# Parameters:
# * offset = 0: _optional_ The offset to use for the empty results.
#
def empty_results offset = 0
result_type.new offset
end
-
+
# Delegates the tokenizing to the query tokenizer.
#
# Parameters:
# * text: The text to tokenize.
#
def tokenized text
@tokenizer.tokenize text
end
-
+
# Gets sorted allocations for the tokens.
#
# This generates the possible allocations, sorted.
#
# TODO Smallify.
@@ -110,50 +141,50 @@
#
# TODO Pass in reduce_to_amount (aka max_allocations)
#
# TODO uniq, score, sort in there
#
- allocations = @weigher.allocations_for tokens
-
+ allocations = @indexes.allocations_for tokens
+
# Callbacks.
#
# TODO Reduce before sort?
#
reduce allocations
remove_from allocations
-
+
# Remove double allocations.
#
allocations.uniq
-
+
# Score the allocations using weights as bias.
#
allocations.calculate_score weights
-
+
# Sort the allocations.
# (allocations are sorted according to score, highest to lowest)
#
allocations.sort
-
+
# Return the allocations.
#
allocations
end
def reduce allocations # :nodoc:
allocations.reduce_to reduce_to_amount if reduce_to_amount
end
-
+
#
#
def remove_from allocations # :nodoc:
allocations.remove identifiers_to_remove
end
#
#
def identifiers_to_remove # :nodoc:
@identifiers_to_remove ||= []
end
-
+
# Display some nice information for the user.
#
def to_s
s = "#{self.class}"
s << ", weights: #{@weights}" unless @weights.empty?
\ No newline at end of file