Module: ActsAsSolr::ClassMethods
- Includes:
- CommonMethods, ParserMethods
- Defined in:
- lib/acts_as_solr/deprecation.rb,
lib/acts_as_solr/class_methods.rb
Constant Summary
Constants included from CommonMethods
ActsAsSolr::CommonMethods::TypeMapping
Instance Method Summary collapse
-
#count_by_solr(query, options = {}) ⇒ Object
returns the total number of documents found in the query specified: Book.count_by_solr 'rails' => 3.
-
#find_by_solr(query, options = {}) ⇒ Object
(also: #search)
Finds instances of a model.
-
#find_id_by_solr(query, options = {}) ⇒ Object
Finds instances of a model and returns an array with the ids: Book.find_id_by_solr “rails” => [1,4,7] The options accepted are the same as find_by_solr.
- #find_multi_search_objects(data, options) ⇒ Object
- #find_with_facet(query, options = {}) ⇒ Object
-
#multi_solr_search(query, options = {}) ⇒ Object
This method can be used to execute a search across multiple models: Book.multi_solr_search “Napoleon OR Tom”, :models => [Movie].
-
#rebuild_solr_index(batch_size = 300, options = {}, &finder) ⇒ Object
(also: #rebuild_index)
It's used to rebuild the Solr index for a specific model.
Methods included from CommonMethods
#get_solr_field_type, #record_id, #solr_add, #solr_batch_add, #solr_batch_add_association, #solr_commit, #solr_delete, #solr_optimize
Instance Method Details
#count_by_solr(query, options = {}) ⇒ Object
returns the total number of documents found in the query specified:
Book.count_by_solr 'rails' => 3
189 190 191 192 |
# File 'lib/acts_as_solr/class_methods.rb', line 189 def count_by_solr(query, = {}) data = parse_query(query, ) data.total_hits end |
#find_by_solr(query, options = {}) ⇒ Object Also known as: search
Finds instances of a model. Terms are ANDed by default, can be overwritten by using OR between terms
Here's a sample (untested) code for your controller:
def search
results = Book.find_by_solr params[:query]
end
For specific fields searching use :filter_queries options
options:
- offset
-
The first document to be retrieved (offset)
-
- page
-
The page to be retrieved
-
- limit
-
The number of rows per page
-
- per_page
-
Alias for limit
-
- filter_queries
-
Use solr filter queries to sort by fields
-
Book.find_by_solr 'ruby', :filter_queries => ['price:5']
- sort
-
Orders (sort by) the result set using a given criteria:
Book.find_by_solr 'ruby', :sort => 'description asc'
-
- field_types
-
This option is deprecated and will be obsolete by version 1.0. There's no need to specify the :field_types anymore when doing a search in a model that specifies a field type for a field. The field types are automatically traced back when they're included.
class Electronic < ActiveRecord::Base acts_as_solr :fields => [{:price => :range_float}] end
- facets
-
This option argument accepts the following arguments:
- fields
-
The fields to be included in the faceted search (Solr's facet.field)
- query
-
The queries to be included in the faceted search (Solr's facet.query)
- zeros
-
Display facets with count of zero. (true|false)
- sort
-
Sorts the faceted resuls by highest to lowest count. (true|false)
- browse
-
This is where the 'drill-down' of the facets work. Accepts an array of fields in the format “facet_field:term”
- mincount
-
Replacement for zeros (it has been deprecated in Solr). Specifies the minimum count necessary for a facet field to be returned. (Solr's facet.mincount) Overrides :zeros if it is specified. Default is 0.
- dates
-
Run date faceted queries using the following arguments:
- fields
-
The fields to be included in the faceted date search (Solr's facet.date). It may be either a String/Symbol or Hash. If it's a hash the options are the same as date_facets minus the fields option (i.e., :start:, :end, :gap, :other, :between). These options if provided will override the base options. (Solr's f.<field_name>.date.<key>=<value>).
- start
-
The lower bound for the first date range for all Date Faceting. Required if :fields is present
- end
-
The upper bound for the last date range for all Date Faceting. Required if :fields is prsent
- gap
-
The size of each date range expressed as an interval to be added to the lower bound using the DateMathParser syntax. Required if :fields is prsent
- hardend
-
A Boolean parameter instructing Solr what do do in the event that facet.date.gap does not divide evenly between facet.date.start and facet.date.end.
- other
-
This param indicates that in addition to the counts for each date range constraint between facet.date.start and facet.date.end, other counds should be calculated. May specify more then one in an Array. The possible options are:
- before
-
all records with lower bound less than start
-
- after
-
all records with upper bound greater than end
-
- between
-
all records with field values between start and end
-
- none
-
compute no other bounds (useful in per field assignment)
-
- all
-
shortcut for before, after, and between
-
- filter
-
Similar to :query option provided by :facets, in that accepts an array of of date queries to limit results. Can not be used as a part of a :field hash. This is the only option that can be used if :fields is not present.
Example:
Electronic.find_by_solr "memory", :facets => {:zeros => false, :sort => true,
:query => ["price:[* TO 200]",
"price:[200 TO 500]",
"price:[500 TO *]"],
:fields => [:category, :manufacturer],
:browse => ["category:Memory","manufacturer:Someone"]}
Examples of date faceting:
basic:
Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:updated_at, :created_at],
:start => 'NOW-10YEARS/DAY', :end => 'NOW/DAY', :gap => '+2YEARS', :other => :before}}
advanced:
Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:updated_at,
{:created_at => {:start => 'NOW-20YEARS/DAY', :end => 'NOW-10YEARS/DAY', :other => [:before, :after]}
}], :start => 'NOW-10YEARS/DAY', :end => 'NOW/DAY', :other => :before, :filter =>
["created_at:[NOW-10YEARS/DAY TO NOW/DAY]", "updated_at:[NOW-1YEAR/DAY TO NOW/DAY]"]}}
filter only:
Electronic.find_by_solr "memory", :facets => {:dates => {:filter => "updated_at:[NOW-1YEAR/DAY TO NOW/DAY]"}}
- scores
-
If set to true this will return the score as a 'solr_score' attribute for each one of the instances found. Does not currently work with find_id_by_solr
books = Book.find_by_solr 'ruby OR splinter', :scores => true books.records.first.solr_score => 1.21321397 books.records.last.solr_score => 0.12321548
- lazy
-
If set to true the search will return objects that will touch the database when you ask for one of their attributes for the first time. Useful when you're using fragment caching based solely on types and ids.
- relevance
-
Sets fields relevance
Book.find_by_solr "zidane", :relevance => {:title => 5, :author => 2}
121 122 123 124 |
# File 'lib/acts_as_solr/class_methods.rb', line 121 def find_by_solr(query, ={}) data = parse_query(query, ) return parse_results(data, ) end |
#find_id_by_solr(query, options = {}) ⇒ Object
Finds instances of a model and returns an array with the ids:
Book.find_id_by_solr "rails" => [1,4,7]
The options accepted are the same as find_by_solr
131 132 133 134 |
# File 'lib/acts_as_solr/class_methods.rb', line 131 def find_id_by_solr(query, ={}) data = parse_query(query, ) return parse_results(data, {:format => :ids}) end |
#find_multi_search_objects(data, options) ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/acts_as_solr/class_methods.rb', line 173 def find_multi_search_objects(data, ) result = [] if [:results_format] == :objects data.hits.each do |doc| k = doc.fetch('id').first.to_s.split(':') result << k[0].constantize.find_by_id(k[1]) end elsif [:results_format] == :ids data.hits.each{|doc| result << {"id" => doc["id"].to_s}} end result end |
#find_with_facet(query, options = {}) ⇒ Object
17 18 19 20 21 |
# File 'lib/acts_as_solr/deprecation.rb', line 17 def find_with_facet(query, ={}) Deprecation.plog "The method find_with_facet is deprecated. Use find_by_solr instead, passing the " + "arguments the same way you used to do with find_with_facet." find_by_solr(query, ) end |
#multi_solr_search(query, options = {}) ⇒ Object
This method can be used to execute a search across multiple models:
Book.multi_solr_search "Napoleon OR Tom", :models => [Movie]
options:
Accepts the same options as find_by_solr plus:
- models
-
The additional models you'd like to include in the search
- results_format
-
Specify the format of the results found
- :objects
-
Will return an array with the results being objects (default). Example:
Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects
- :ids
-
Will return an array with the ids of each entry found. Example:
Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :ids => [{"id" => "Movie:1"},{"id" => Book:1}]
Where the value of each array is as Model:instance_id
- scores
-
If set to true this will return the score as a 'solr_score' attribute for each one of the instances found. Does not currently work with find_id_by_solr
books = Book.multi_solr_search 'ruby OR splinter', :scores => true books.records.first.solr_score => 1.21321397 books.records.last.solr_score => 0.12321548
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/acts_as_solr/class_methods.rb', line 158 def multi_solr_search(query, = {}) .update(:results_format => :objects) unless [:results_format] data = parse_query(query, ) if data.nil? or data.total_hits == 0 return SearchResults.new(:docs => [], :total => 0) end result = find_multi_search_objects(data, ) if [:scores] and [:results_format] == :objects add_scores(result, data) end SearchResults.new :docs => result, :total => data.total_hits end |
#rebuild_solr_index(batch_size = 300, options = {}, &finder) ⇒ Object Also known as: rebuild_index
It's used to rebuild the Solr index for a specific model.
Book.rebuild_solr_index
If batch_size is greater than 0, adds will be done in batches. NOTE: If using sqlserver, be sure to use a finder with an explicit order. Non-edge versions of rails do not handle pagination correctly for sqlserver without an order clause.
If a finder block is given, it will be called to retrieve the items to index. This can be very useful for things such as updating based on conditions or using eager loading for indexed associations.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/acts_as_solr/class_methods.rb', line 205 def rebuild_solr_index(batch_size=300, = {}, &finder) finder ||= lambda do |ar, | ar.all .merge!({:order => self.primary_key, :include => configuration[:solr_includes].keys}) end start_time = Time.now [:offset] ||= 0 [:threads] ||= 2 [:delayed_job] &= defined?(Delayed::Job) if batch_size > 0 items_processed = 0 offset = [:offset] end_reached = false threads = [] mutex = Mutex.new queue = Queue.new loop do items = finder.call(self, {:limit => batch_size, :offset => offset}) add_batch = items.collect { |content| content.to_solr_doc } offset += items.size end_reached = items.size == 0 break if end_reached if [:threads] == threads.size threads.first.join threads.shift end queue << [items, add_batch] threads << Thread.new do iteration_start = Time.now iteration_items, iteration_add_batch = queue.pop(true) if [:delayed_job] delay.solr_add iteration_add_batch else solr_add iteration_add_batch solr_commit end last_id = iteration_items.last.id time_so_far = Time.now - start_time iteration_time = Time.now - iteration_start mutex.synchronize do items_processed += iteration_items.size if [:delayed_job] logger.info "#{Process.pid}: #{items_processed} items for #{self.name} have been sent to Delayed::Job in #{'%.3f' % time_so_far}s at #{'%.3f' % (items_processed / time_so_far)} items/sec. Last id: #{last_id}" else logger.info "#{Process.pid}: #{items_processed} items for #{self.name} have been batch added to index in #{'%.3f' % time_so_far}s at #{'%.3f' % (items_processed / time_so_far)} items/sec. Last id: #{last_id}" end end end end solr_commit if [:delayed_job] threads.each{ |t| t.join } else items = finder.call(self, {}) items.each { |content| content.solr_save } items_processed = items.size end if items_processed > 0 solr_optimize time_elapsed = Time.now - start_time logger.info "Index for #{self.name} has been rebuilt (took #{'%.3f' % time_elapsed}s)" else "Nothing to index for #{self.name}" end end |