module Sunspot module DSL #:nodoc: # # This class presents a DSL for constructing queries using the # Sunspot.search method. Methods of this class are available inside the # search block. Much of the DSL's functionality is implemented by this # class's superclasses, Sunspot::DSL::FieldQuery and Sunspot::DSL::Scope # # See Sunspot.search for usage examples # class StandardQuery < FieldQuery include Paginatable, Adjustable # Specify a phrase that should be searched as fulltext. Only +text+ # fields are searched - see DSL::Fields.text # # Keyword search is executed using Solr's dismax handler, which strikes # a good balance between powerful and foolproof. In particular, # well-matched quotation marks can be used to group phrases, and the # + and - modifiers work as expected. All other special Solr boolean # syntax is escaped, and mismatched quotes are ignored entirely. # # This method can optionally take a block, which is evaluated by the # Fulltext DSL class, and exposes several powerful dismax features. # # ==== Parameters # # keywords:: phrase to perform fulltext search on # # ==== Options # # :fields:: # List of fields that should be searched for keywords. Defaults to all # fields configured for the types under search. # :highlight:: # If true, perform keyword highlighting on all searched fields. If an # array of field names, perform highlighting on the specified fields. # This can also be called from within the fulltext block. # :minimum_match:: # The minimum number of search terms that a result must match. By # default, all search terms must match; if the number of search terms # is less than this number, the default behavior applies. # :tie:: # A tiebreaker coefficient for scores derived from subqueries that are # lower-scoring than the maximum score subquery. Typically a near-zero # value is useful. See # http://wiki.apache.org/solr/DisMaxRequestHandler#tie_.28Tie_breaker.29 # for more information. # :query_phrase_slop:: # The number of words that can appear between the words in a # user-entered phrase (i.e., keywords in quotes) and still match. For # instance, in a search for "\"great pizza\"" with a phrase slop of 1, # "great pizza" and "great big pizza" will match, but "great monster of # a pizza" will not. Default behavior is a query phrase slop of zero. # def fulltext(keywords, options = {}, &block) if keywords && !(keywords.to_s =~ /^\s*$/) fulltext_query = @query.add_fulltext(keywords) if field_names = options.delete(:fields) Util.Array(field_names).each do |field_name| @setup.text_fields(field_name).each do |field| fulltext_query.add_fulltext_field(field, field.default_boost) end end end if minimum_match = options.delete(:minimum_match) fulltext_query.minimum_match = minimum_match.to_i end if tie = options.delete(:tie) fulltext_query.tie = tie.to_f end if query_phrase_slop = options.delete(:query_phrase_slop) fulltext_query.query_phrase_slop = query_phrase_slop.to_i end if highlight_field_names = options.delete(:highlight) if highlight_field_names == true fulltext_query.add_highlight else highlight_fields = [] Util.Array(highlight_field_names).each do |field_name| highlight_fields.concat(@setup.text_fields(field_name)) end fulltext_query.add_highlight(highlight_fields) end end if block && fulltext_query fulltext_dsl = Fulltext.new(fulltext_query, @setup) Util.instance_eval_or_call( fulltext_dsl, &block ) end if !field_names && (!fulltext_dsl || !fulltext_dsl.fields_added?) @setup.all_text_fields.each do |field| unless fulltext_query.has_fulltext_field?(field) unless fulltext_dsl && fulltext_dsl.exclude_fields.include?(field.name) fulltext_query.add_fulltext_field(field, field.default_boost) end end end end end end alias_method :keywords, :fulltext # # Scope the search by geographical distance from a given point. # +coordinates+ should either respond to #first and #last (e.g. a # two-element array), or to #lat and one of #lng, #lon, or #long. # +options+ should be one or both of the following: # # :distance:: The maximum distance in miles from which results can come # :sort:: # Whether to sort by distance from these coordinates. If other sorts are # specified, they take precedence over distance sort. # def near(coordinates, options) if options.respond_to?(:to_f) options = { :distance => options } end @query.add_location_restriction(coordinates, options) end end end end