Class: Sunspot::DSL::FieldQuery
- Defined in:
- lib/sunspot/dsl/field_query.rb
Overview
Provides an API for areas of the query DSL that operate on specific fields. This functionality is provided by the query DSL and the dynamic query DSL.
Direct Known Subclasses
Instance Method Summary collapse
- #dynamic(base_name, &block) ⇒ Object
-
#facet(*field_names, &block) ⇒ Object
Request a facet on the search query.
-
#group(*field_names, &block) ⇒ Object
Specify a field for result grouping.
-
#initialize(search, query, setup) ⇒ FieldQuery
constructor
:nodoc:.
-
#order_by(field_name, direction = nil) ⇒ Object
Specify the order that results should be returned in.
-
#order_by_function(*args) ⇒ Object
Specify that results should be ordered based on a FunctionQuery - wiki.apache.org/solr/FunctionQuery Solr 3.1 and up.
-
#order_by_geodist(field_name, lat, lon, direction = nil) ⇒ Object
Specify that the results should be ordered based on their distance from a given point.
-
#order_by_random ⇒ Object
DEPRECATED Use
order_by(:random)
. - #stats(*field_names, &block) ⇒ Object
Methods inherited from Scope
#all_of, #any_of, #text_fields, #with, #without
Constructor Details
#initialize(search, query, setup) ⇒ FieldQuery
:nodoc:
9 10 11 12 |
# File 'lib/sunspot/dsl/field_query.rb', line 9 def initialize(search, query, setup) #:nodoc: @search, @query = search, query super(query.scope, setup) end |
Instance Method Details
#dynamic(base_name, &block) ⇒ Object
350 351 352 353 354 355 356 |
# File 'lib/sunspot/dsl/field_query.rb', line 350 def dynamic(base_name, &block) dynamic_field_factory = @setup.dynamic_field_factory(base_name) Sunspot::Util.instance_eval_or_call( FieldQuery.new(@search, @query, dynamic_field_factory), &block ) end |
#facet(*field_names, &block) ⇒ Object
Request a facet on the search query. A facet is a feature of Solr that determines the number of documents that match the existing search and an additional criterion. This allows you to build powerful drill-down interfaces for search, at each step presenting the searcher with a set of refinements that are known to return results.
In Sunspot, each facet returns zero or more rows, each of which represents a particular criterion conjoined with the actual query being performed. For field facets, each row represents a particular value for a given field. For query facets, each row represents an arbitrary scope; the facet itself is just a means of logically grouping the scopes.
Examples
Field Facets
A field facet is specified by passing one or more Symbol arguments to this method:
Sunspot.search(Post) do
with(:blog_id, 1)
facet(:category_id)
end
The facet specified above will have a row for each category_id that is present in a document which also has a blog_id of 1.
Multiselect Facets
In certain circumstances, it is beneficial to exclude certain query scopes from a facet; the most common example is multi-select faceting, where the user has selected a certain value, but the facet should still show all options that would be available if they had not:
Sunspot.search(Post) do
with(:blog_id, 1)
category_filter = with(:category_id, 2)
facet(:category_id, :exclude => category_filter)
end
Although the results of the above search will be restricted to those with a category_id of 2, the category_id facet will operate as if a category had not been selected, allowing the user to select additional categories (which will presumably be ORed together).
It possible to exclude multiple filters by passing an array:
Sunspot.search(Post) do
with(:blog_id, 1)
category_filter = with(:category_id, 2)
= with(:author_id, 3)
facet(:category_id,
:exclude => [category_filter, ].compact)
end
You should consider using .compact
to ensure that the array does not contain any nil values.
<strong>As far as I can tell, Solr only supports multi-select with field facets; if :exclude
is passed to a query facet, this method will raise an error. Also, the :only
and :extra
options use query faceting under the hood, so these can’t be used with :extra
either. </strong>
Query Facets
A query facet is a collection of arbitrary scopes, each of which represents a row. This is specified by passing a block into the #facet method; the block then contains one or more row
blocks, each of which creates a query facet row. The row
blocks follow the usual Sunspot scope DSL.
For example, a query facet can be used to facet over a set of ranges:
Sunspot.search(Post) do
facet(:average_rating) do
row(1.0..2.0) do
with(:average_rating, 1.0..2.0)
end
row(2.0..3.0) do
with(:average_rating, 2.0..3.0)
end
row(3.0..4.0) do
with(:average_rating, 3.0..4.0)
end
row(4.0..5.0) do
with(:average_rating, 4.0..5.0)
end
end
end
Note that the arguments to the facet
and row
methods simply provide labels for the facet and its rows, so that they can be retrieved and identified from the Search object. They are not passed to Solr and no semantic meaning is attached to them. The label for facet
should be a symbol; the label for row
can be whatever you’d like.
Range Facets
One can use the Range Faceting feature on any date field or any numeric field that supports range queries. This is particularly useful for the cases in the past where one might stitch together a series of range queries (as facet by query) for things like prices, etc.
For example faceting over average ratings can be done as follows:
Sunspot.search(Post) do
facet :average_rating, :range => 1..5, :range_interval => 1
end
Parameters
- field_names…<Symbol>
-
fields for which to return field facets
Options
- :sort<Symbol>
-
Either :count (values matching the most terms first) or :index (lexical)
- :limit<Integer>
-
The maximum number of facet rows to return
- :offset<Integer>
-
The offset from which to start returning facet rows
- :minimum_count<Integer>
-
The minimum count a facet row must have to be returned
- :zeros<Boolean>
-
Return facet rows for which there are no matches (equivalent to :minimum_count => 0). Default is false.
- :exclude<Object,Array>
-
Exclude one or more filters when performing the faceting (see Multiselect Faceting above). The object given for this argument should be the return value(s) of a scoping method (
with
,any_of
,all_of
, etc.). <strong>Only can be used for field facets that do not use the:extra
or:only
options.</strong> - :name<Symbol>
-
Give a custom name to a field facet. The main use case for this option is for requesting the same field facet multiple times, using different filter exclusions (see Multiselect Faceting above). If you pass this option, it is also the argument that should be passed to Search#facet when retrieving the facet result.
- :only<Array>
-
Only return facet rows for the given values. Useful if you are only interested in faceting on a subset of values for a given field. <strong>Only applies to field facets.</strong>
- :extra<Symbol,Array>
-
One or more of :any and :none. :any returns a facet row with a count of all matching documents that have some value for this field. :none returns a facet row with a count of all matching documents that have no value for this field. The facet row(s) corresponding to the extras have a value of the symbol passed. <strong>Only applies to field facets.</strong>
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 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/sunspot/dsl/field_query.rb', line 240 def facet(*field_names, &block) = Sunspot::Util.(field_names) if block if field_names.length != 1 raise( ArgumentError, "wrong number of arguments (#{field_names.length} for 1)" ) end search_facet = @search.add_query_facet(field_names.first, ) Sunspot::Util.instance_eval_or_call( QueryFacet.new(@query, @setup, search_facet, ), &block ) elsif [:only] if .has_key?(:exclude) raise( ArgumentError, "can't use :exclude with :only (see documentation)" ) end field_names.each do |field_name| field = @setup.field(field_name) search_facet = @search.add_field_facet(field, ) Util.Array([:only]).each do |value| facet = Sunspot::Query::QueryFacet.new facet.add_positive_restriction(field, Sunspot::Query::Restriction::EqualTo, value) @query.add_query_facet(facet) search_facet.add_row(value, facet.to_boolean_phrase) end end else field_names.each do |field_name| search_facet = nil field = @setup.field(field_name) facet = if [:time_range] unless field.type.is_a?(Sunspot::Type::TimeType) raise( ArgumentError, ':time_range can only be specified for Date or Time fields' ) end search_facet = @search.add_date_facet(field, ) Sunspot::Query::DateFieldFacet.new(field, ) elsif [:range] unless [Sunspot::Type::TimeType, Sunspot::Type::FloatType, Sunspot::Type::IntegerType ].inject(false){|res,type| res || field.type.is_a?(type)} raise( ArgumentError, ':range can only be specified for date or numeric fields' ) end search_facet = @search.add_range_facet(field, ) Sunspot::Query::RangeFacet.new(field, ) else search_facet = @search.add_field_facet(field, ) Sunspot::Query::FieldFacet.new(field, ) end @query.add_field_facet(facet) Util.Array([:extra]).each do |extra| if .has_key?(:exclude) raise( ArgumentError, "can't use :exclude with :extra (see documentation)" ) end extra_facet = Sunspot::Query::QueryFacet.new case extra when :any extra_facet.add_negated_restriction( field, Sunspot::Query::Restriction::EqualTo, nil ) when :none extra_facet.add_positive_restriction( field, Sunspot::Query::Restriction::EqualTo, nil ) else raise( ArgumentError, "Allowed values for :extra are :any and :none" ) end search_facet.add_row(extra, extra_facet.to_boolean_phrase) @query.add_query_facet(extra_facet) end end end end |
#group(*field_names, &block) ⇒ Object
Specify a field for result grouping. Grouping groups documents with a common field value, return only the top document per group.
More information in the Solr documentation: <wiki.apache.org/solr/FieldCollapsing>
Parameters
- field_name<Symbol>
-
the field to use for grouping
72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/sunspot/dsl/field_query.rb', line 72 def group(*field_names, &block) field_names.each do |field_name| field = @setup.field(field_name) group = @query.add_group(Sunspot::Query::FieldGroup.new(field)) @search.add_field_group(field) if block Sunspot::Util.instance_eval_or_call( FieldGroup.new(@setup, group), &block ) end end end |
#order_by(field_name, direction = nil) ⇒ Object
Specify the order that results should be returned in. This method can be called multiple times; precedence will be in the order given.
Parameters
- field_name<Symbol>
-
the field to use for ordering
- direction<Symbol>
-
:asc or :desc (default :asc)
22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/sunspot/dsl/field_query.rb', line 22 def order_by(field_name, direction = nil) sort = if special = Sunspot::Query::Sort.special(field_name) special.new(direction) else Sunspot::Query::Sort::FieldSort.new( @setup.field(field_name), direction ) end @query.add_sort(sort) end |
#order_by_function(*args) ⇒ Object
Specify that results should be ordered based on a FunctionQuery - wiki.apache.org/solr/FunctionQuery Solr 3.1 and up
For example, to order by field1 + (field2*field3):
order_by_function :sum, :field1, [:product, :field2, :field3], :desc
Parameters
- function_name<Symbol>
-
the function to run
- arguments
-
the arguments for this function.
-
Symbol for a field or function name
-
Array for a nested function
-
String for a literal constant
-
- direction<Symbol>
-
:asc or :desc
376 377 378 379 380 |
# File 'lib/sunspot/dsl/field_query.rb', line 376 def order_by_function(*args) @query.add_sort( Sunspot::Query::Sort::FunctionSort.new(@setup,args) ) end |
#order_by_geodist(field_name, lat, lon, direction = nil) ⇒ Object
Specify that the results should be ordered based on their distance from a given point.
Parameters
- field_name<Symbol>
-
the field that stores the location (declared as ‘latlon`)
- lat<Numeric>
-
the reference latitude
- lon<Numeric>
-
the reference longitude
- direction<Symbol>
-
:asc or :desc (default :asc)
49 50 51 52 53 |
# File 'lib/sunspot/dsl/field_query.rb', line 49 def order_by_geodist(field_name, lat, lon, direction = nil) @query.add_sort( Sunspot::Query::Sort::GeodistSort.new(@setup.field(field_name), lat, lon, direction) ) end |
#order_by_random ⇒ Object
DEPRECATED Use order_by(:random)
58 59 60 |
# File 'lib/sunspot/dsl/field_query.rb', line 58 def order_by_random order_by(:random) end |
#stats(*field_names, &block) ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/sunspot/dsl/field_query.rb', line 334 def stats(*field_names, &block) = Sunspot::Util.(field_names) field_names.each do |field_name| field = @setup.field(field_name) query_stats = @query.add_stats( Sunspot::Query::FieldStats.new(field, ) ) search_stats = @search.add_field_stats(field) Sunspot::Util.instance_eval_or_call( FieldStats.new(query_stats, @setup, search_stats), &block) if block end end |