sunspot 2.0.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Appraisals +7 -0
- data/Gemfile +0 -2
- data/History.txt +10 -0
- data/lib/sunspot.rb +55 -17
- data/lib/sunspot/adapters.rb +68 -18
- data/lib/sunspot/batcher.rb +1 -1
- data/lib/sunspot/configuration.rb +4 -2
- data/lib/sunspot/data_extractor.rb +36 -6
- data/lib/sunspot/dsl.rb +4 -3
- data/lib/sunspot/dsl/adjustable.rb +2 -2
- data/lib/sunspot/dsl/field_query.rb +69 -16
- data/lib/sunspot/dsl/field_stats.rb +25 -0
- data/lib/sunspot/dsl/fields.rb +28 -8
- data/lib/sunspot/dsl/fulltext.rb +9 -1
- data/lib/sunspot/dsl/group.rb +118 -0
- data/lib/sunspot/dsl/paginatable.rb +4 -1
- data/lib/sunspot/dsl/scope.rb +19 -10
- data/lib/sunspot/dsl/search.rb +1 -1
- data/lib/sunspot/dsl/spellcheckable.rb +14 -0
- data/lib/sunspot/dsl/standard_query.rb +63 -35
- data/lib/sunspot/field.rb +76 -4
- data/lib/sunspot/field_factory.rb +60 -11
- data/lib/sunspot/indexer.rb +70 -18
- data/lib/sunspot/query.rb +5 -4
- data/lib/sunspot/query/abstract_field_facet.rb +0 -2
- data/lib/sunspot/query/abstract_fulltext.rb +76 -0
- data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
- data/lib/sunspot/query/bbox.rb +5 -1
- data/lib/sunspot/query/common_query.rb +31 -6
- data/lib/sunspot/query/composite_fulltext.rb +58 -8
- data/lib/sunspot/query/date_field_json_facet.rb +25 -0
- data/lib/sunspot/query/dismax.rb +25 -71
- data/lib/sunspot/query/field_json_facet.rb +19 -0
- data/lib/sunspot/query/field_list.rb +15 -0
- data/lib/sunspot/query/field_stats.rb +61 -0
- data/lib/sunspot/query/function_query.rb +1 -2
- data/lib/sunspot/query/geo.rb +1 -1
- data/lib/sunspot/query/geofilt.rb +8 -3
- data/lib/sunspot/query/group.rb +46 -0
- data/lib/sunspot/query/group_query.rb +17 -0
- data/lib/sunspot/query/join.rb +88 -0
- data/lib/sunspot/query/more_like_this.rb +1 -1
- data/lib/sunspot/query/pagination.rb +12 -4
- data/lib/sunspot/query/range_json_facet.rb +28 -0
- data/lib/sunspot/query/restriction.rb +99 -13
- data/lib/sunspot/query/sort.rb +41 -0
- data/lib/sunspot/query/sort_composite.rb +7 -0
- data/lib/sunspot/query/spellcheck.rb +19 -0
- data/lib/sunspot/query/standard_query.rb +24 -2
- data/lib/sunspot/query/text_field_boost.rb +1 -3
- data/lib/sunspot/schema.rb +12 -3
- data/lib/sunspot/search.rb +4 -2
- data/lib/sunspot/search/abstract_search.rb +93 -43
- data/lib/sunspot/search/cursor_paginated_collection.rb +32 -0
- data/lib/sunspot/search/field_facet.rb +4 -4
- data/lib/sunspot/search/field_json_facet.rb +33 -0
- data/lib/sunspot/search/field_stats.rb +21 -0
- data/lib/sunspot/search/hit.rb +6 -1
- data/lib/sunspot/search/hit_enumerable.rb +4 -1
- data/lib/sunspot/search/json_facet_row.rb +40 -0
- data/lib/sunspot/search/json_facet_stats.rb +23 -0
- data/lib/sunspot/search/paginated_collection.rb +1 -0
- data/lib/sunspot/search/query_group.rb +74 -0
- data/lib/sunspot/search/standard_search.rb +70 -3
- data/lib/sunspot/search/stats_facet.rb +25 -0
- data/lib/sunspot/search/stats_json_row.rb +82 -0
- data/lib/sunspot/search/stats_row.rb +68 -0
- data/lib/sunspot/session.rb +62 -37
- data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +6 -4
- data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +16 -8
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +2 -2
- data/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +1 -1
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +4 -2
- data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +1 -1
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +6 -4
- data/lib/sunspot/setup.rb +42 -0
- data/lib/sunspot/type.rb +20 -0
- data/lib/sunspot/util.rb +78 -14
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/adapters_spec.rb +40 -15
- data/spec/api/batcher_spec.rb +15 -15
- data/spec/api/binding_spec.rb +3 -3
- data/spec/api/class_set_spec.rb +6 -6
- data/spec/api/data_extractor_spec.rb +39 -0
- data/spec/api/hit_enumerable_spec.rb +32 -9
- data/spec/api/indexer/attributes_spec.rb +35 -30
- data/spec/api/indexer/batch_spec.rb +8 -7
- data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
- data/spec/api/indexer/fixed_fields_spec.rb +16 -11
- data/spec/api/indexer/fulltext_spec.rb +8 -8
- data/spec/api/indexer/removal_spec.rb +24 -14
- data/spec/api/indexer_spec.rb +2 -2
- data/spec/api/query/advanced_manipulation_examples.rb +3 -3
- data/spec/api/query/connectives_examples.rb +26 -14
- data/spec/api/query/dsl_spec.rb +24 -6
- data/spec/api/query/dynamic_fields_examples.rb +18 -18
- data/spec/api/query/faceting_examples.rb +80 -61
- data/spec/api/query/fulltext_examples.rb +194 -40
- data/spec/api/query/function_spec.rb +116 -13
- data/spec/api/query/geo_examples.rb +8 -12
- data/spec/api/query/group_spec.rb +27 -5
- data/spec/api/query/highlighting_examples.rb +26 -26
- data/spec/api/query/join_spec.rb +19 -0
- data/spec/api/query/more_like_this_spec.rb +40 -27
- data/spec/api/query/ordering_pagination_examples.rb +37 -23
- data/spec/api/query/scope_examples.rb +39 -39
- data/spec/api/query/spatial_examples.rb +3 -3
- data/spec/api/query/spellcheck_examples.rb +20 -0
- data/spec/api/query/standard_spec.rb +3 -1
- data/spec/api/query/stats_examples.rb +66 -0
- data/spec/api/query/text_field_scoping_examples.rb +5 -5
- data/spec/api/query/types_spec.rb +4 -4
- data/spec/api/search/cursor_paginated_collection_spec.rb +35 -0
- data/spec/api/search/dynamic_fields_spec.rb +4 -4
- data/spec/api/search/faceting_spec.rb +55 -52
- data/spec/api/search/highlighting_spec.rb +7 -7
- data/spec/api/search/hits_spec.rb +43 -29
- data/spec/api/search/paginated_collection_spec.rb +19 -18
- data/spec/api/search/results_spec.rb +13 -13
- data/spec/api/search/search_spec.rb +3 -3
- data/spec/api/search/stats_spec.rb +94 -0
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +23 -16
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +16 -4
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +11 -11
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +15 -14
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +3 -3
- data/spec/api/session_proxy/spec_helper.rb +1 -1
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +40 -26
- data/spec/api/session_spec.rb +78 -38
- data/spec/api/sunspot_spec.rb +7 -4
- data/spec/helpers/integration_helper.rb +11 -1
- data/spec/helpers/query_helper.rb +1 -1
- data/spec/helpers/search_helper.rb +30 -0
- data/spec/integration/atomic_updates_spec.rb +58 -0
- data/spec/integration/dynamic_fields_spec.rb +31 -20
- data/spec/integration/faceting_spec.rb +252 -39
- data/spec/integration/field_grouping_spec.rb +47 -15
- data/spec/integration/field_lists_spec.rb +57 -0
- data/spec/integration/geospatial_spec.rb +34 -8
- data/spec/integration/highlighting_spec.rb +8 -8
- data/spec/integration/indexing_spec.rb +7 -6
- data/spec/integration/join_spec.rb +45 -0
- data/spec/integration/keyword_search_spec.rb +68 -38
- data/spec/integration/local_search_spec.rb +4 -4
- data/spec/integration/more_like_this_spec.rb +7 -7
- data/spec/integration/scoped_search_spec.rb +193 -74
- data/spec/integration/spellcheck_spec.rb +119 -0
- data/spec/integration/stats_spec.rb +88 -0
- data/spec/integration/stored_fields_spec.rb +1 -1
- data/spec/integration/test_pagination.rb +4 -4
- data/spec/integration/unicode_spec.rb +1 -1
- data/spec/mocks/adapters.rb +36 -0
- data/spec/mocks/connection.rb +5 -3
- data/spec/mocks/photo.rb +32 -1
- data/spec/mocks/post.rb +18 -3
- data/spec/spec_helper.rb +13 -8
- data/sunspot.gemspec +6 -4
- data/tasks/rdoc.rake +22 -14
- metadata +101 -44
- data/lib/sunspot/dsl/field_group.rb +0 -57
- data/lib/sunspot/query/field_group.rb +0 -37
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class FieldJsonFacet < AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
def initialize(field, options, setup)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def field_name_with_local_params
|
10
|
+
{
|
11
|
+
@field.name => {
|
12
|
+
type: 'terms',
|
13
|
+
field: @field.indexed_name,
|
14
|
+
}.merge!(init_params)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query #:nodoc:
|
3
|
+
|
4
|
+
# This DSL represents only fields that would come out of the results of the search type.
|
5
|
+
class FieldList
|
6
|
+
def initialize(list)
|
7
|
+
@list = list
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_params
|
11
|
+
{ :fl => @list }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class FieldStats
|
4
|
+
def initialize(field, options)
|
5
|
+
@field, @options = field, options
|
6
|
+
@facets = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_facet field
|
10
|
+
@facets << field
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_json_facet(json_facet)
|
14
|
+
@json_facet = json_facet
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_params
|
18
|
+
params = {}
|
19
|
+
if !@json_facet.nil?
|
20
|
+
params['json.facet'] = recursive_add_stats(@json_facet.get_params).to_json
|
21
|
+
else
|
22
|
+
params.merge!(:stats => true, :"stats.field" => [@field.indexed_name])
|
23
|
+
params[facet_key] = @facets.map(&:indexed_name) unless @facets.empty?
|
24
|
+
end
|
25
|
+
params
|
26
|
+
end
|
27
|
+
|
28
|
+
STATS_FUNCTIONS = [:min, :max, :sum, :avg, :sumsq]
|
29
|
+
|
30
|
+
def recursive_add_stats(query)
|
31
|
+
query.keys.each do |k|
|
32
|
+
if !query[k][:facet].nil?
|
33
|
+
query[k][:facet] = recursive_add_stats(query[k][:facet])
|
34
|
+
end
|
35
|
+
query[k][:facet] ||= {}
|
36
|
+
query[k][:sort] = { @options[:sort] => @options[:sort_type]||'desc' } unless @options[:sort].nil?
|
37
|
+
query[k][:facet].merge!(json_stats_params)
|
38
|
+
end
|
39
|
+
query
|
40
|
+
end
|
41
|
+
|
42
|
+
def json_stats_params
|
43
|
+
params = {}
|
44
|
+
STATS_FUNCTIONS.each { |s| params[s] = "#{s.to_s}(#{@field.indexed_name})" }
|
45
|
+
unless @options[:stats].nil?
|
46
|
+
to_remove = STATS_FUNCTIONS - @options[:stats]
|
47
|
+
to_remove.map { |s| params.delete(s)}
|
48
|
+
end
|
49
|
+
params
|
50
|
+
end
|
51
|
+
|
52
|
+
def facet_key
|
53
|
+
qualified_param 'facet'
|
54
|
+
end
|
55
|
+
|
56
|
+
def qualified_param name
|
57
|
+
:"f.#{@field.indexed_name}.stats.#{name}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -4,7 +4,6 @@ module Sunspot
|
|
4
4
|
# Abstract class for function queries.
|
5
5
|
#
|
6
6
|
class FunctionQuery
|
7
|
-
include RSolr::Char
|
8
7
|
|
9
8
|
def ^(y)
|
10
9
|
@boost_amount = y
|
@@ -34,7 +33,7 @@ module Sunspot
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def to_s
|
37
|
-
"#{escape(@field.indexed_name)}" << (@boost_amount ? "^#{@boost_amount}" : "")
|
36
|
+
"#{Util.escape(@field.indexed_name)}" << (@boost_amount ? "^#{@boost_amount}" : "")
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
data/lib/sunspot/query/geo.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Query
|
3
3
|
class Geofilt
|
4
|
+
include Filter
|
5
|
+
attr_reader :field
|
6
|
+
|
4
7
|
def initialize(field, lat, lon, radius, options = {})
|
5
8
|
@field, @lat, @lon, @radius, @options = field, lat, lon, radius, options
|
6
9
|
end
|
7
10
|
|
8
|
-
def
|
11
|
+
def to_boolean_phrase
|
9
12
|
func = @options[:bbox] ? "bbox" : "geofilt"
|
13
|
+
"{!#{func} sfield=#{@field.indexed_name} pt=#{@lat},#{@lon} d=#{@radius}}"
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
{:fq =>
|
16
|
+
def to_params
|
17
|
+
{:fq => to_filter_query}
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# A Group groups by the unique values of a given field, or by given queries.
|
5
|
+
#
|
6
|
+
class Group
|
7
|
+
attr_accessor :limit, :truncate, :ngroups
|
8
|
+
attr_reader :fields, :queries
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@sort = SortComposite.new
|
12
|
+
@fields = []
|
13
|
+
@queries = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_field(field)
|
17
|
+
if field.multiple?
|
18
|
+
raise(ArgumentError, "#{field.name} cannot be used for grouping because it is a multiple-value field")
|
19
|
+
end
|
20
|
+
@fields << field
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_query(query)
|
24
|
+
@queries << query
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_sort(sort)
|
28
|
+
@sort << sort
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_params
|
32
|
+
params = {
|
33
|
+
:group => 'true',
|
34
|
+
:"group.ngroups" => @ngroups.nil? ? 'true' : @ngroups.to_s
|
35
|
+
}
|
36
|
+
|
37
|
+
params.merge!(@sort.to_params('group.'))
|
38
|
+
params[:"group.field"] = @fields.map(&:indexed_name) if @fields.any?
|
39
|
+
params[:"group.query"] = @queries.map(&:to_boolean_phrase) if @queries.any?
|
40
|
+
params[:"group.limit"] = @limit if @limit
|
41
|
+
params[:"group.truncate"] = @truncate if @truncate
|
42
|
+
params
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# Representation of a GroupQuery, which allows the searcher to specify a
|
5
|
+
# query to group matching documents. This is essentially a conjunction,
|
6
|
+
# with an extra instance variable containing the label for the group.
|
7
|
+
#
|
8
|
+
class GroupQuery < Connective::Conjunction #:nodoc:
|
9
|
+
attr_reader :label
|
10
|
+
|
11
|
+
def initialize(label, negated = false)
|
12
|
+
super(negated)
|
13
|
+
@label = label
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
|
4
|
+
#
|
5
|
+
# Solr full-text queries use Solr's JoinRequestHandler.
|
6
|
+
#
|
7
|
+
class Join < AbstractFulltext
|
8
|
+
attr_writer :minimum_match, :phrase_slop, :query_phrase_slop, :tie
|
9
|
+
|
10
|
+
def initialize(keywords, target, from, to)
|
11
|
+
@keywords = keywords
|
12
|
+
@target = target
|
13
|
+
@from = from
|
14
|
+
@to = to
|
15
|
+
|
16
|
+
@fulltext_fields = {}
|
17
|
+
|
18
|
+
@minimum_match = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# The query as Solr parameters
|
23
|
+
#
|
24
|
+
def to_params
|
25
|
+
params = { :q => @keywords }
|
26
|
+
params[:fl] = '* score'
|
27
|
+
params[:qf] = @fulltext_fields.values.map { |field| field.to_boosted_field }.join(' ')
|
28
|
+
params[:defType] = 'join'
|
29
|
+
params[:mm] = @minimum_match if @minimum_match
|
30
|
+
|
31
|
+
params
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Serialize the query as a Solr nested subquery.
|
36
|
+
#
|
37
|
+
def to_subquery
|
38
|
+
params = self.to_params
|
39
|
+
params.delete :defType
|
40
|
+
params.delete :fl
|
41
|
+
|
42
|
+
keywords = escape_quotes(params.delete(:q))
|
43
|
+
options = params.map { |key, value| escape_param(key, value) }.join(' ')
|
44
|
+
q_name = "q#{@target.name}#{self.object_id}"
|
45
|
+
|
46
|
+
{
|
47
|
+
:q => "_query_:\"{!join from=#{@from} to=#{@to} v=$#{q_name}}\"",
|
48
|
+
q_name => "_query_:\"{!field f=type}#{@target.name}\"+_query_:\"{!edismax #{options}}#{keywords}\""
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Assign a new boost query and return it.
|
54
|
+
#
|
55
|
+
def create_boost_query(factor)
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Add a boost function
|
60
|
+
#
|
61
|
+
def add_boost_function(function_query)
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Add a fulltext field to be searched, with optional boost.
|
66
|
+
#
|
67
|
+
def add_fulltext_field(field, boost = nil)
|
68
|
+
super if field.is_a?(Sunspot::JoinField) &&
|
69
|
+
field.target == @target && field.from == @from && field.to == @to
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Add a phrase field for extra boost.
|
74
|
+
#
|
75
|
+
def add_phrase_field(field, boost = nil)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Set highlighting options for the query. If fields is empty, the
|
80
|
+
# Highlighting object won't pass field names at all, which means
|
81
|
+
# the dismax's :qf parameter will be used by Solr.
|
82
|
+
#
|
83
|
+
def add_highlight(fields=[], options={})
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -50,7 +50,7 @@ module Sunspot
|
|
50
50
|
params[:"mlt.fl"] = @fields.keys.join(",")
|
51
51
|
boosted_fields = @fields.values.select { |field| field.boost }
|
52
52
|
unless boosted_fields.empty?
|
53
|
-
params[:qf] = boosted_fields.map do |field|
|
53
|
+
params[:"mlt.qf"] = boosted_fields.map do |field|
|
54
54
|
field.to_boosted_field
|
55
55
|
end.join(' ')
|
56
56
|
end
|
@@ -6,14 +6,18 @@ module Sunspot
|
|
6
6
|
# reference to it and updates it if pagination is changed.
|
7
7
|
#
|
8
8
|
class Pagination #:nodoc:
|
9
|
-
attr_reader :page, :per_page, :offset
|
9
|
+
attr_reader :page, :per_page, :offset, :cursor
|
10
10
|
|
11
|
-
def initialize(page = nil, per_page = nil, offset = nil)
|
12
|
-
self.offset, self.page, self.per_page = offset, page, per_page
|
11
|
+
def initialize(page = nil, per_page = nil, offset = nil, cursor = nil)
|
12
|
+
self.offset, self.page, self.per_page, self.cursor = offset, page, per_page, cursor
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_params
|
16
|
-
|
16
|
+
if @cursor
|
17
|
+
{ :cursorMark => @cursor, :rows => rows }
|
18
|
+
else
|
19
|
+
{ :start => start, :rows => rows }
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
def page=(page)
|
@@ -28,6 +32,10 @@ module Sunspot
|
|
28
32
|
@offset = offset.to_i
|
29
33
|
end
|
30
34
|
|
35
|
+
def cursor=(cursor)
|
36
|
+
@cursor = cursor if cursor
|
37
|
+
end
|
38
|
+
|
31
39
|
private
|
32
40
|
|
33
41
|
def start
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class RangeJsonFacet < AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
SECONDS_IN_DAY = 86400
|
6
|
+
|
7
|
+
def initialize(field, options, setup)
|
8
|
+
raise Exception.new("Need to specify a range") if options[:range].nil?
|
9
|
+
@start = options[:range].first
|
10
|
+
@end = options[:range].last
|
11
|
+
@gap = options[:gap] || SECONDS_IN_DAY
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def field_name_with_local_params
|
16
|
+
{
|
17
|
+
@field.name => {
|
18
|
+
type: 'range',
|
19
|
+
field: @field.indexed_name,
|
20
|
+
start: @field.to_indexed(@start),
|
21
|
+
end: @field.to_indexed(@end),
|
22
|
+
gap: @gap
|
23
|
+
}.merge!(init_params)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -11,7 +11,7 @@ module Sunspot
|
|
11
11
|
# Array:: Collection of restriction class names
|
12
12
|
#
|
13
13
|
def names
|
14
|
-
constants -
|
14
|
+
constants - abstract_constants
|
15
15
|
end
|
16
16
|
|
17
17
|
#
|
@@ -22,6 +22,17 @@ module Sunspot
|
|
22
22
|
@types ||= {}
|
23
23
|
@types[restriction_name.to_sym] ||= const_get(Sunspot::Util.camel_case(restriction_name.to_s))
|
24
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
#
|
29
|
+
# Return the names of all abstract restriction classes that should not
|
30
|
+
# be made available to the DSL. Considers abstract classes are any class
|
31
|
+
# ending with '::Base' or containing a namespace prefixed with 'Abstract'
|
32
|
+
#
|
33
|
+
def abstract_constants
|
34
|
+
constants.grep(/(^|::)(Base$|Abstract)/)
|
35
|
+
end
|
25
36
|
end
|
26
37
|
|
27
38
|
#
|
@@ -38,7 +49,6 @@ module Sunspot
|
|
38
49
|
#
|
39
50
|
class Base #:nodoc:
|
40
51
|
include Filter
|
41
|
-
include RSolr::Char
|
42
52
|
|
43
53
|
RESERVED_WORDS = Set['AND', 'OR', 'NOT']
|
44
54
|
|
@@ -68,11 +78,14 @@ module Sunspot
|
|
68
78
|
# on whether this restriction is negated.
|
69
79
|
#
|
70
80
|
def to_boolean_phrase
|
81
|
+
phrase = []
|
82
|
+
phrase << @field.local_params if @field.respond_to? :local_params
|
71
83
|
unless negated?
|
72
|
-
to_positive_boolean_phrase
|
84
|
+
phrase << to_positive_boolean_phrase
|
73
85
|
else
|
74
|
-
to_negated_boolean_phrase
|
86
|
+
phrase << to_negated_boolean_phrase
|
75
87
|
end
|
88
|
+
phrase.join
|
76
89
|
end
|
77
90
|
|
78
91
|
#
|
@@ -89,7 +102,7 @@ module Sunspot
|
|
89
102
|
# String:: Boolean phrase for restriction in the positive
|
90
103
|
#
|
91
104
|
def to_positive_boolean_phrase
|
92
|
-
"#{escape(@field.indexed_name)}:#{to_solr_conditional}"
|
105
|
+
"#{Util.escape(@field.indexed_name)}:#{to_solr_conditional}"
|
93
106
|
end
|
94
107
|
|
95
108
|
#
|
@@ -122,7 +135,7 @@ module Sunspot
|
|
122
135
|
|
123
136
|
protected
|
124
137
|
|
125
|
-
#
|
138
|
+
#
|
126
139
|
# Return escaped Solr API representation of given value
|
127
140
|
#
|
128
141
|
# ==== Parameters
|
@@ -135,7 +148,7 @@ module Sunspot
|
|
135
148
|
# String:: Solr API representation of given value
|
136
149
|
#
|
137
150
|
def solr_value(value = @value)
|
138
|
-
solr_value = escape(@field.to_indexed(value))
|
151
|
+
solr_value = Util.escape(@field.to_indexed(value))
|
139
152
|
if RESERVED_WORDS.include?(solr_value)
|
140
153
|
%Q("#{solr_value}")
|
141
154
|
else
|
@@ -145,9 +158,13 @@ module Sunspot
|
|
145
158
|
end
|
146
159
|
|
147
160
|
class InRadius < Base
|
148
|
-
def initialize(negated, field,
|
149
|
-
@lat, @lon, @radius =
|
150
|
-
super negated, field,
|
161
|
+
def initialize(negated, field, *value)
|
162
|
+
@lat, @lon, @radius = value
|
163
|
+
super negated, field, value
|
164
|
+
end
|
165
|
+
|
166
|
+
def negate
|
167
|
+
self.class.new(!@negated, @field, *@value)
|
151
168
|
end
|
152
169
|
|
153
170
|
private
|
@@ -156,6 +173,17 @@ module Sunspot
|
|
156
173
|
end
|
157
174
|
end
|
158
175
|
|
176
|
+
class InBoundingBox < Base
|
177
|
+
def initialize(negated, field, first_corner, second_corner)
|
178
|
+
@bbox = Sunspot::Query::Bbox.new(field, first_corner, second_corner)
|
179
|
+
super negated, field, [first_corner, second_corner]
|
180
|
+
end
|
181
|
+
|
182
|
+
def to_solr_conditional
|
183
|
+
@bbox.to_solr_conditional
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
159
187
|
#
|
160
188
|
# Results must have field with value equal to given value. If the value
|
161
189
|
# is nil, results must have no value for the given field.
|
@@ -165,7 +193,7 @@ module Sunspot
|
|
165
193
|
unless @value.nil?
|
166
194
|
super
|
167
195
|
else
|
168
|
-
"#{escape(@field.indexed_name)}:[* TO *]"
|
196
|
+
"#{Util.escape(@field.indexed_name)}:[* TO *]"
|
169
197
|
end
|
170
198
|
end
|
171
199
|
|
@@ -273,10 +301,23 @@ module Sunspot
|
|
273
301
|
# Results must have field with value included in given collection
|
274
302
|
#
|
275
303
|
class AnyOf < Base
|
304
|
+
|
305
|
+
def negated?
|
306
|
+
if @value.empty?
|
307
|
+
false
|
308
|
+
else
|
309
|
+
super
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
276
313
|
private
|
277
314
|
|
278
315
|
def to_solr_conditional
|
279
|
-
|
316
|
+
if @value.empty?
|
317
|
+
"[* TO *]"
|
318
|
+
else
|
319
|
+
"(#{@value.map { |v| solr_value v } * ' OR '})"
|
320
|
+
end
|
280
321
|
end
|
281
322
|
end
|
282
323
|
|
@@ -285,10 +326,22 @@ module Sunspot
|
|
285
326
|
# collection (only makes sense for fields with multiple values)
|
286
327
|
#
|
287
328
|
class AllOf < Base
|
329
|
+
def negated?
|
330
|
+
if @value.empty?
|
331
|
+
false
|
332
|
+
else
|
333
|
+
super
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
288
337
|
private
|
289
338
|
|
290
339
|
def to_solr_conditional
|
291
|
-
|
340
|
+
if @value.empty?
|
341
|
+
"[* TO *]"
|
342
|
+
else
|
343
|
+
"(#{@value.map { |v| solr_value v } * ' AND '})"
|
344
|
+
end
|
292
345
|
end
|
293
346
|
end
|
294
347
|
|
@@ -303,6 +356,39 @@ module Sunspot
|
|
303
356
|
"#{solr_value(@value)}*"
|
304
357
|
end
|
305
358
|
end
|
359
|
+
|
360
|
+
class AbstractRange < Between
|
361
|
+
private
|
362
|
+
|
363
|
+
def operation
|
364
|
+
@operation || self.class.name.split('::').last
|
365
|
+
end
|
366
|
+
|
367
|
+
def solr_value(value = @value)
|
368
|
+
@field.to_indexed(value)
|
369
|
+
end
|
370
|
+
|
371
|
+
def to_positive_boolean_phrase
|
372
|
+
"_query_:\"{!field f=#{@field.indexed_name} op=#{operation}}#{solr_value}\""
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
class Containing < AbstractRange
|
377
|
+
def initialize(negated, field, value)
|
378
|
+
@operation = 'Contains'
|
379
|
+
super
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
class Intersecting < AbstractRange
|
384
|
+
def initialize(negated, field, value)
|
385
|
+
@operation = 'Intersects'
|
386
|
+
super
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
class Within < AbstractRange
|
391
|
+
end
|
306
392
|
end
|
307
393
|
end
|
308
394
|
end
|