module Sunspot module Search # # Hit objects represent the raw information returned by Solr for a single # document. As well as the primary key and class name, hit objects give # access to stored field values, keyword relevance score, and keyword # highlighting. # class Hit SPECIAL_KEYS = Set.new(%w(id type score)) #:nodoc: # # Primary key of object associated with this hit, as string. # attr_reader :primary_key # # Class name of object associated with this hit, as string. # attr_reader :class_name # # Keyword relevance score associated with this result. Nil if this hit # is not from a keyword search. # attr_reader :score # attr_writer :result #:nodoc: def initialize(raw_hit, highlights, search) #:nodoc: @class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2] @score = raw_hit['score'] @search = search @stored_values = raw_hit @stored_cache = {} @highlights = highlights end # # Returns all highlights for this hit when called without parameters. # When a field_name is provided, returns only the highlight for this field. # def highlights(field_name = nil) if field_name.nil? highlights_cache.values.flatten else highlights_cache[field_name.to_sym] end || [] end # # Return the first highlight found for a given field, or nil if there is # none. # def highlight(field_name) highlights(field_name).first end # # Retrieve stored field value. For any attribute field configured with # :stored => true, the Hit object will contain the stored value for # that field. The value of this field will be typecast according to the # type of the field. # # ==== Parameters # # field_name:: # The name of the field for which to retrieve the stored value. # dynamic_field_name:: # If you want to access a stored dynamic field, this should be the # dynamic component of the field name. # def stored(field_name, dynamic_field_name = nil) field_key = if dynamic_field_name [field_name.to_sym, dynamic_field_name.to_sym] else field_name.to_sym end return @stored_cache[field_key] if @stored_cache.has_key?(field_key) @stored_cache[field_key] = stored_value(field_name, dynamic_field_name) end # # Retrieve the instance associated with this hit. This is lazy-loaded, but # the first time it is called on any hit, all the hits for the search will # load their instances using the adapter's #load_all method. # def result return @result if defined?(@result) @search.populate_hits @result end alias_method :instance, :result def inspect #:nodoc: "#" end private def setup @setup ||= Sunspot::Setup.for(Util.full_const_get(@class_name)) end def highlights_cache @highlights_cache ||= begin cache = {} if @highlights @highlights.each_pair do |indexed_field_name, highlight_strings| field_name = indexed_field_name.sub(/_[a-z]+$/, '').to_sym cache[field_name] = highlight_strings.map do |highlight_string| Highlight.new(field_name, highlight_string) end end end cache end end def stored_value(field_name, dynamic_field_name) setup.stored_fields(field_name, dynamic_field_name).each do |field| if value = @stored_values[field.indexed_name] case value when Array return value.map { |item| field.cast(item) } else return field.cast(value) end end end nil end end end end