Class: Sunspot::Search::AbstractSearch

Inherits:
Object
  • Object
show all
Defined in:
lib/sunspot/search/abstract_search.rb

Overview

This class encapsulates the results of a Solr search. It provides access to search results, total result count, facets, and pagination information. Instances of Search are returned by the Sunspot.search and Sunspot.new_search methods.

Direct Known Subclasses

MoreLikeThisSearch, StandardSearch

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, setup, query, configuration) ⇒ AbstractSearch

:nodoc:



21
22
23
24
25
26
# File 'lib/sunspot/search/abstract_search.rb', line 21

def initialize(connection, setup, query, configuration) #:nodoc:
  @connection, @setup, @query = connection, setup, query
  @query.paginate(1, configuration.pagination.default_per_page)
  @facets = []
  @facets_by_name = {}
end

Instance Attribute Details

#facetsObject (readonly)

Retrieve all facet objects defined for this search, in order they were defined. To retrieve an individual facet by name, use #facet()



17
18
19
# File 'lib/sunspot/search/abstract_search.rb', line 17

def facets
  @facets
end

#queryObject (readonly)

:nodoc:



18
19
20
# File 'lib/sunspot/search/abstract_search.rb', line 18

def query
  @query
end

#request_handlerObject

Returns the value of attribute request_handler.



19
20
21
# File 'lib/sunspot/search/abstract_search.rb', line 19

def request_handler
  @request_handler
end

Instance Method Details

#add_date_facet(field, options) ⇒ Object

:nodoc:



287
288
289
290
# File 'lib/sunspot/search/abstract_search.rb', line 287

def add_date_facet(field, options) #:nodoc:
  name = (options[:name] || field.name)
  add_facet(name, DateFacet.new(field, self, options))
end

#add_field_facet(field, options = {}) ⇒ Object

:nodoc:



278
279
280
281
# File 'lib/sunspot/search/abstract_search.rb', line 278

def add_field_facet(field, options = {}) #:nodoc:
  name = (options[:name] || field.name)
  add_facet(name, FieldFacet.new(field, self, options))
end

#add_query_facet(name, options) ⇒ Object

:nodoc:



283
284
285
# File 'lib/sunspot/search/abstract_search.rb', line 283

def add_query_facet(name, options) #:nodoc:
  add_facet(name, QueryFacet.new(name, self, options))
end

#build(&block) ⇒ Object

Build this search using a DSL block. This method can be called more than once on an unexecuted search (e.g., Sunspot.new_search) in order to build a search incrementally.

Example

search = Sunspot.new_search(Post)
search.build do
  with(:published_at).less_than Time.now
end
search.execute


247
248
249
250
# File 'lib/sunspot/search/abstract_search.rb', line 247

def build(&block)
  Util.instance_eval_or_call(dsl, &block)
  self
end

#data_accessor_for(clazz) ⇒ Object

Get the data accessor that will be used to load a particular class out of persistent storage. Data accessors can implement any methods that may be useful for refining how data is loaded out of storage. When building a search manually (e.g., using the Sunspot#new_search method), this should be used before calling #execute(). Use the Sunspot::DSL::Search#data_accessor_for method when building searches using the block DSL.



229
230
231
232
# File 'lib/sunspot/search/abstract_search.rb', line 229

def data_accessor_for(clazz) #:nodoc:
  (@data_accessors ||= {})[clazz.name.to_sym] ||=
    Adapters::DataAccessor.create(clazz)
end

#dynamic_facet(base_name, dynamic_name) ⇒ Object

Deprecated in favor of optional second argument to #facet



174
175
176
# File 'lib/sunspot/search/abstract_search.rb', line 174

def dynamic_facet(base_name, dynamic_name) #:nodoc:
  facet(base_name, dynamic_name)
end

#each_hit_with_resultObject

Convenience method to iterate over hit and result objects. Block is yielded a Sunspot::Server::Hit instance and a Sunspot::Server::Result instance.

Note that this method iterates over verified hits (see #hits method for more information).



104
105
106
107
108
# File 'lib/sunspot/search/abstract_search.rb', line 104

def each_hit_with_result
  verified_hits.each do |hit|
    yield(hit, hit.result)
  end
end

#executeObject

Execute the search on the Solr instance and store the results. If you use Sunspot#search() to construct your searches, there is no need to call this method as it has already been called. If you use Sunspot#new_search(), you will need to call this method after building the query.



35
36
37
38
39
40
# File 'lib/sunspot/search/abstract_search.rb', line 35

def execute
  reset
  params = @query.to_params
  @solr_result = @connection.post "#{request_handler}", :params => params, :headers => { 'Content-Type' => 'application/x-www-form-urlencoded' }
  self
end

#execute!Object

:nodoc: deprecated



42
43
44
# File 'lib/sunspot/search/abstract_search.rb', line 42

def execute! #:nodoc: deprecated
  execute
end

#facet(name, dynamic_name = nil) ⇒ Object

Get the facet object for the given name. ‘name` can either be the name given to a query facet, or the field name of a field facet. Returns a Sunspot::Facet object.

Parameters

name<Symbol>

Name of the field to return the facet for, or the name given to the query facet when the search was constructed.

dynamic_name<Symbol>

If faceting on a dynamic field, this is the dynamic portion of the field name.

Example:

search = Sunspot.search(Post) do
  facet :category_ids
  dynamic :custom do
    facet :cuisine
  end
  facet :age do
    row 'Less than a month' do
      with(:published_at).greater_than(1.month.ago)
    end
    row 'Less than a year' do
      with(:published_at, 1.year.ago..1.month.ago)
    end
    row 'More than a year' do
      with(:published_at).less_than(1.year.ago)
    end
  end
end
search.facet(:category_ids)
  #=> Facet for :category_ids field
search.facet(:custom, :cuisine)
  #=> Facet for the dynamic field :cuisine in the :custom field definition
search.facet(:age)
  #=> Facet for the query facet named :age


161
162
163
164
165
166
167
168
169
# File 'lib/sunspot/search/abstract_search.rb', line 161

def facet(name, dynamic_name = nil)
  if name
    if dynamic_name
      @facets_by_name[:"#{name}:#{dynamic_name}"]
    else
      @facets_by_name[name.to_sym]
    end
  end
end

#facet_responseObject

:nodoc:



178
179
180
# File 'lib/sunspot/search/abstract_search.rb', line 178

def facet_response #:nodoc:
  @solr_result['facet_counts']
end

#fq_response_headerObject

Decomposes the Solr “Filter Query” (fq) parameter array further into a hash that can be easily digested when constructing FieldFacet.rows. Specifically, it is used to add a boolean “selected” attribute on each row so it’s easy to pick out which of the facets returned in a result are part of the originating query. This is useful for doing something like generating “undo” links, or showing checkbox initial state as checked.

Filter query values with keys ending in ‘_im’ and ‘_s’ are processed into their constituent parts.

solr_response_header[‘fq’] is an array of strings of the form, for example: fq: [“type:Package”,

 "amenities_ids_im:(9 AND 12)",
 "neighborhood_s:(East\ Village OR Chelsea)",
 "capacity_max_is:[30 TO *]"
]

which is converted to the equivalent hash: fq_response_header: [“type” => “Package”,

 "amenties_ids_im" => ["9", "12"],
 "neighborhood_s" => ["East Village", "Chelsea"],
 "capacity_max_is" => "[30 TO *]"
]


205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/sunspot/search/abstract_search.rb', line 205

def fq_response_header
  @fq_response_header ||=
    begin
      h = Hash.new
      solr_response_header['params']['fq'].each do |filter_query|
        field, value = filter_query.split(':')
        field = field.gsub(/^\{\!tag=.*?\}/, '') # strip exclude tags
        value = value.gsub(/^\(|\)$|\\/, '') # strips surrounding parens and \,
        value = value.split(/ AND | OR /) if facet_split[0] =~ /_im$|_s$/
        h[field] = value
      end
      h
    end
end

#hits(options = {}) ⇒ Object Also known as: raw_results

Access raw Solr result information. Returns a collection of Hit objects that contain the class name, primary key, keyword relevance score (if applicable), and any stored fields.

Options (options)

:verify

Only return hits that reference objects that actually exist in the data store. This causes results to be eager-loaded from the data store, unlike the normal behavior of this method, which only loads the referenced results when Hit#result is first called.

Returns

Array

Ordered collection of Hit objects



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/sunspot/search/abstract_search.rb', line 79

def hits(options = {})
  if options[:verify]
    verified_hits
  else
    @hits ||=
      begin
        hits = if solr_response && solr_response['docs']
          solr_response['docs'].map do |doc|
            Hit.new(doc, highlights_for(doc), self)
          end
        end
        paginate_collection(hits || [])
      end
  end
end

#inspectObject

:nodoc:



274
275
276
# File 'lib/sunspot/search/abstract_search.rb', line 274

def inspect #:nodoc:
  "<Sunspot::Search:#{query.to_params.inspect}>"
end

#populate_hitsObject

Populate the Hit objects with their instances. This is invoked the first time any hit has its instance requested, and all hits are loaded as a batch.



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/sunspot/search/abstract_search.rb', line 257

def populate_hits #:nodoc:
  id_hit_hash = Hash.new { |h, k| h[k] = {} }
  hits.each do |hit|
    id_hit_hash[hit.class_name][hit.primary_key] = hit
  end
  id_hit_hash.each_pair do |class_name, hits|
    ids = hits.map { |id, hit| hit.primary_key }
    data_accessor = data_accessor_for(Util.full_const_get(class_name))
    hits_for_class = id_hit_hash[class_name]
    data_accessor.load_all(ids).each do |result|
      hit = hits_for_class.delete(Adapters::InstanceAdapter.adapt(result).id.to_s)
      hit.result = result
    end
    hits_for_class.values.each { |hit| hit.result = nil }
  end
end

#resultsObject

Get the collection of results as instantiated objects. If WillPaginate is available, the results will be a WillPaginate::Collection instance; if not, it will be a vanilla Array.

If not all of the results referenced by the Solr hits actually exist in the data store, Sunspot will only return the results that do exist.

Returns

WillPaginate::Collection or Array

Instantiated result objects



58
59
60
# File 'lib/sunspot/search/abstract_search.rb', line 58

def results
  @results ||= paginate_collection(verified_hits.map { |hit| hit.instance })
end

#totalObject

The total number of documents matching the query parameters

Returns

Integer

Total matching documents



117
118
119
# File 'lib/sunspot/search/abstract_search.rb', line 117

def total
  @total ||= solr_response['numFound'] || 0
end