lib/thinking_sphinx/search.rb in dpickett-thinking-sphinx-1.1.12 vs lib/thinking_sphinx/search.rb in dpickett-thinking-sphinx-1.1.23

- old
+ new

@@ -1,5 +1,7 @@ +require 'thinking_sphinx/search/facets' + module ThinkingSphinx # Once you've got those indexes in and built, this is the stuff that # matters - how to search! This class provides a generic search # interface - which you can use to search all your indexed models at once. # Most times, you will just want a specific model's results - to search and @@ -11,10 +13,12 @@ :all_attributes => false, :class_facet => true } class << self + include ThinkingSphinx::Search::Facets + # Searches for results that match the parameters provided. Will only # return the ids for the matching objects. See #search for syntax # examples. # # Note that this only searches the Sphinx index, with no ActiveRecord @@ -216,10 +220,14 @@ # Grouping is done via three parameters within the options hash # * <tt>:group_function</tt> determines the way grouping is done # * <tt>:group_by</tt> determines the field which is used for grouping # * <tt>:group_clause</tt> determines the sorting order # + # As a convenience, you can also use + # * <tt>:group</tt> + # which sets :group_by and defaults to :group_function of :attr + # # === group_function # # Valid values for :group_function are # * <tt>:day</tt>, <tt>:week</tt>, <tt>:month</tt>, <tt>:year</tt> - Grouping is done by the respective timeframes. # * <tt>:attr</tt>, <tt>:attrpair</tt> - Grouping is done by the specified attributes(s) @@ -352,15 +360,13 @@ query = args.clone # an array options = query.extract_options! retry_search_on_stale_index(query, options) do results, client = search_results(*(query + [options])) + + log "Sphinx Error: #{results[:error]}", :error if results[:error] - ::ActiveRecord::Base.logger.error( - "Sphinx Error: #{results[:error]}" - ) if results[:error] - klass = options[:class] page = options[:page] ? options[:page].to_i : 1 ThinkingSphinx::Collection.create_from_results(results, page, client.limit, options) end @@ -388,13 +394,13 @@ stale_ids |= e.ids # For logging options[:without_ids] = Array(options[:without_ids]) | e.ids # Actual exclusion tries = stale_retries_left - ::ActiveRecord::Base.logger.debug("Sphinx Stale Ids (%s %s left): %s" % [ - tries, (tries==1 ? 'try' : 'tries'), stale_ids.join(', ') - ]) + log "Sphinx Stale Ids (%s %s left): %s" % [ + tries, (tries==1 ? 'try' : 'tries'), stale_ids.join(', ') + ] retry end end @@ -430,25 +436,10 @@ rescue Errno::ECONNREFUSED => err raise ThinkingSphinx::ConnectionError, "Connection to Sphinx Daemon (searchd) failed." end end - # Model.facets *args - # ThinkingSphinx::Search.facets *args - # ThinkingSphinx::Search.facets *args, :all_attributes => true - # ThinkingSphinx::Search.facets *args, :class_facet => false - # - def facets(*args) - options = args.extract_options! - - if options[:class] - facets_for_model options[:class], args, options - else - facets_for_all_models args, options - end - end - private # This method handles the common search functionality, and returns both # the result hash and the client. Not super elegant, but it'll do for # the moment. @@ -472,15 +463,18 @@ client.limit = options[:per_page].to_i if options[:per_page] page = options[:page] ? options[:page].to_i : 1 page = 1 if page <= 0 client.offset = (page - 1) * client.limit - + begin - ::ActiveRecord::Base.logger.debug "Sphinx: #{query}" - results = client.query query - ::ActiveRecord::Base.logger.debug "Sphinx Result: #{results[:matches].collect{|m| m[:attributes]["sphinx_internal_id"]}.inspect}" + log "Sphinx: #{query}" + results = client.query(query, '*', options[:comment] || '') + log "Sphinx Result:" + log results[:matches].collect { |m| + m[:attributes]["sphinx_internal_id"] + }.inspect rescue Errno::ECONNREFUSED => err raise ThinkingSphinx::ConnectionError, "Connection to Sphinx Daemon (searchd) failed." end return results, client @@ -516,10 +510,16 @@ end hash end end + # Group by defaults using :group + if options[:group] + options[:group_by] = options[:group].to_s + options[:group_function] ||= :attr + end + [ :max_matches, :match_mode, :sort_mode, :sort_by, :id_range, :group_by, :group_function, :group_clause, :group_distinct, :cut_off, :retry_count, :retry_delay, :index_weights, :rank_mode, :max_query_time, :field_weights, :filters, :anchor, :limit @@ -640,15 +640,15 @@ attributes = klass ? klass.sphinx_indexes.collect { |index| index.attributes.collect { |attrib| attrib.unique_name } }.flatten : [] lat_attr = klass ? klass.sphinx_indexes.collect { |index| - index.options[:latitude_attr] + index.local_options[:latitude_attr] }.compact.first : nil lon_attr = klass ? klass.sphinx_indexes.collect { |index| - index.options[:longitude_attr] + index.local_options[:longitude_attr] }.compact.first : nil lat_attr = options[:latitude_attr] if options[:latitude_attr] lat_attr ||= :lat if attributes.include?(:lat) lat_attr ||= :latitude if attributes.include?(:latitude) @@ -693,11 +693,11 @@ client.sort_by = order.to_s.concat("_sort") else client.sort_by = order.to_s end when String - client.sort_mode = :extended + client.sort_mode = :extended unless options[:sort_mode] client.sort_by = sorted_fields_to_attributes(order, fields) else # do nothing end @@ -716,76 +716,12 @@ } string end - def facets_for_model(klass, args, options) - hash = ThinkingSphinx::FacetCollection.new args + [options] - options = options.clone.merge! facet_query_options - - klass.sphinx_facets.inject(hash) do |hash, facet| - unless facet.name == :class && !options[:class_facet] - options[:group_by] = facet.attribute_name - hash.add_from_results facet, search(*(args + [options])) - end - - hash - end - end - - def facets_for_all_models(args, options) - options = GlobalFacetOptions.merge(options) - hash = ThinkingSphinx::FacetCollection.new args + [options] - options = options.merge! facet_query_options - - facet_names(options).inject(hash) do |hash, name| - options[:group_by] = name - hash.add_from_results name, search(*(args + [options])) - hash - end - end - - def facet_query_options - config = ThinkingSphinx::Configuration.instance - max = config.configuration.searchd.max_matches || 1000 - - { - :group_function => :attr, - :limit => max, - :max_matches => max - } - end - - def facet_classes(options) - options[:classes] || ThinkingSphinx.indexed_models.collect { |model| - model.constantize - } - end - - def facet_names(options) - classes = facet_classes(options) - names = options[:all_attributes] ? - facet_names_for_all_classes(classes) : - facet_names_common_to_all_classes(classes) - - names.delete "class_crc" unless options[:class_facet] - names - end - - def facet_names_for_all_classes(classes) - classes.collect { |klass| - klass.sphinx_facets.collect { |facet| facet.attribute_name } - }.flatten.uniq - end - - def facet_names_common_to_all_classes(classes) - facet_names_for_all_classes(classes).select { |name| - classes.all? { |klass| - klass.sphinx_facets.detect { |facet| - facet.attribute_name == name - } - } - } + def log(message, method = :debug) + return if ::ActiveRecord::Base.logger.nil? + ::ActiveRecord::Base.logger.send method, message end end end end