sunspot 2.3.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Appraisals +4 -4
- data/lib/sunspot/adapters.rb +15 -1
- data/lib/sunspot/data_extractor.rb +36 -6
- data/lib/sunspot/dsl/fields.rb +16 -0
- data/lib/sunspot/dsl/fulltext.rb +1 -1
- data/lib/sunspot/dsl/group.rb +10 -0
- data/lib/sunspot/dsl/scope.rb +17 -17
- data/lib/sunspot/dsl/standard_query.rb +29 -1
- data/lib/sunspot/dsl.rb +2 -2
- data/lib/sunspot/field.rb +15 -4
- data/lib/sunspot/indexer.rb +37 -8
- data/lib/sunspot/query/abstract_fulltext.rb +7 -3
- data/lib/sunspot/query/abstract_json_field_facet.rb +3 -0
- data/lib/sunspot/query/composite_fulltext.rb +21 -2
- data/lib/sunspot/query/date_field_json_facet.rb +2 -16
- data/lib/sunspot/query/dismax.rb +10 -4
- data/lib/sunspot/query/function_query.rb +25 -1
- data/lib/sunspot/query/group.rb +4 -5
- data/lib/sunspot/query/join.rb +3 -5
- data/lib/sunspot/query/range_json_facet.rb +5 -2
- data/lib/sunspot/query/restriction.rb +18 -13
- data/lib/sunspot/query/standard_query.rb +12 -0
- data/lib/sunspot/search/abstract_search.rb +1 -1
- data/lib/sunspot/search/field_json_facet.rb +14 -3
- data/lib/sunspot/search/hit.rb +6 -1
- data/lib/sunspot/session.rb +9 -1
- data/lib/sunspot/setup.rb +69 -0
- data/lib/sunspot/util.rb +4 -11
- data/lib/sunspot/version.rb +1 -1
- data/lib/sunspot.rb +9 -1
- data/spec/api/adapters_spec.rb +13 -0
- data/spec/api/data_extractor_spec.rb +39 -0
- data/spec/api/indexer/removal_spec.rb +87 -0
- data/spec/api/query/connective_boost_examples.rb +85 -0
- data/spec/api/query/fulltext_examples.rb +6 -12
- data/spec/api/query/join_spec.rb +2 -2
- data/spec/api/query/standard_spec.rb +10 -0
- data/spec/api/search/hits_spec.rb +14 -0
- data/spec/api/setup_spec.rb +99 -0
- data/spec/api/sunspot_spec.rb +3 -0
- data/spec/helpers/indexer_helper.rb +22 -0
- data/spec/integration/atomic_updates_spec.rb +169 -5
- data/spec/integration/faceting_spec.rb +68 -34
- data/spec/integration/field_grouping_spec.rb +19 -0
- data/spec/integration/field_lists_spec.rb +16 -0
- data/spec/integration/geospatial_spec.rb +15 -0
- data/spec/integration/join_spec.rb +64 -0
- data/spec/integration/scoped_search_spec.rb +78 -0
- data/spec/mocks/adapters.rb +33 -0
- data/spec/mocks/connection.rb +6 -0
- data/spec/mocks/photo.rb +19 -5
- data/spec/mocks/post.rb +35 -1
- data/sunspot.gemspec +0 -2
- metadata +14 -8
- data/gemfiles/.gitkeep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c13ef43c3d9e3c45ca9d1ccc170ba55947797e788911fda1982b817d34207c5d
|
4
|
+
data.tar.gz: 8a2dc3da8797d0ff4945c99732c9808e1ff9d06f94d0611b932a20cc49210d08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbdf307d46210db9f3430a7a46d615709aa181c61c2400f6e42d23edd5dfa0c619ecb249cf148eb7215d4dd37d9907c630acf4d13ec83319cff1cbdd2652882e
|
7
|
+
data.tar.gz: f77be8b5ee7ea9226565214951f4af0930b994f9fe568b4c79ac7d0733d414644d32018b4bdfb0ebd23a19b30ecece2c45da5d29b8bd46e28aafaf33ff58796f
|
data/Appraisals
CHANGED
data/lib/sunspot/adapters.rb
CHANGED
@@ -55,6 +55,20 @@ module Sunspot
|
|
55
55
|
@instance = instance
|
56
56
|
end
|
57
57
|
|
58
|
+
#
|
59
|
+
# An ID prefix to be added to the index_id
|
60
|
+
#
|
61
|
+
# ==== Returns
|
62
|
+
#
|
63
|
+
# String:: ID prefix for use in index ID to determine
|
64
|
+
# the shard a document is sent to for indexing
|
65
|
+
#
|
66
|
+
def id_prefix
|
67
|
+
setup = Sunspot::Setup.for(@instance.class)
|
68
|
+
|
69
|
+
setup && setup.id_prefix_for(@instance)
|
70
|
+
end
|
71
|
+
|
58
72
|
#
|
59
73
|
# The universally-unique ID for this instance that will be stored in solr
|
60
74
|
#
|
@@ -63,7 +77,7 @@ module Sunspot
|
|
63
77
|
# String:: ID for use in Solr
|
64
78
|
#
|
65
79
|
def index_id #:nodoc:
|
66
|
-
InstanceAdapter.index_id_for(@instance.class.name, id)
|
80
|
+
InstanceAdapter.index_id_for("#{id_prefix}#{@instance.class.name}", id)
|
67
81
|
end
|
68
82
|
|
69
83
|
class <<self
|
@@ -5,16 +5,46 @@ module Sunspot
|
|
5
5
|
# method, which takes an object and returns the value extracted from it.
|
6
6
|
#
|
7
7
|
module DataExtractor #:nodoc: all
|
8
|
+
#
|
9
|
+
# Abstract extractor to perform common actions on extracted values
|
10
|
+
#
|
11
|
+
class AbstractExtractor
|
12
|
+
BLACKLIST_REGEXP = /[\x0-\x8\xB\xC\xE-\x1F\x7f\uFFFE-\uFFFF]/
|
13
|
+
|
14
|
+
def value_for(object)
|
15
|
+
extract_value_from(object)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def extract_value_from(object)
|
21
|
+
case object
|
22
|
+
when String
|
23
|
+
remove_blacklisted_chars(object)
|
24
|
+
when Array
|
25
|
+
object.map { |o| extract_value_from(o) }
|
26
|
+
when Hash
|
27
|
+
object.inject({}) { |h, (k, v)| h.merge(extract_value_from(k) => extract_value_from(v)) }
|
28
|
+
else
|
29
|
+
object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_blacklisted_chars(object)
|
34
|
+
object.gsub(BLACKLIST_REGEXP, '')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
8
38
|
#
|
9
39
|
# AttributeExtractors extract data by simply calling a method on the block.
|
10
40
|
#
|
11
|
-
class AttributeExtractor
|
41
|
+
class AttributeExtractor < AbstractExtractor
|
12
42
|
def initialize(attribute_name)
|
13
43
|
@attribute_name = attribute_name
|
14
44
|
end
|
15
45
|
|
16
46
|
def value_for(object)
|
17
|
-
object.send(@attribute_name)
|
47
|
+
super object.send(@attribute_name)
|
18
48
|
end
|
19
49
|
end
|
20
50
|
|
@@ -24,26 +54,26 @@ module Sunspot
|
|
24
54
|
# as the argument to the block. Either way, the return value of the block is
|
25
55
|
# the value returned by the extractor.
|
26
56
|
#
|
27
|
-
class BlockExtractor
|
57
|
+
class BlockExtractor < AbstractExtractor
|
28
58
|
def initialize(&block)
|
29
59
|
@block = block
|
30
60
|
end
|
31
61
|
|
32
62
|
def value_for(object)
|
33
|
-
Util.instance_eval_or_call(object, &@block)
|
63
|
+
super Util.instance_eval_or_call(object, &@block)
|
34
64
|
end
|
35
65
|
end
|
36
66
|
|
37
67
|
#
|
38
68
|
# Constant data extractors simply return the same value for every object.
|
39
69
|
#
|
40
|
-
class Constant
|
70
|
+
class Constant < AbstractExtractor
|
41
71
|
def initialize(value)
|
42
72
|
@value = value
|
43
73
|
end
|
44
74
|
|
45
75
|
def value_for(object)
|
46
|
-
@value
|
76
|
+
super @value
|
47
77
|
end
|
48
78
|
end
|
49
79
|
end
|
data/lib/sunspot/dsl/fields.rb
CHANGED
@@ -55,6 +55,22 @@ module Sunspot
|
|
55
55
|
@setup.add_document_boost(attr_name, &block)
|
56
56
|
end
|
57
57
|
|
58
|
+
#
|
59
|
+
# If you use the compositeId router for shards, you can send documents
|
60
|
+
# with a prefix in the document ID which will be used to calculate the
|
61
|
+
# hash Solr uses to determine the shard a document is sent to for indexing.
|
62
|
+
# The prefix can be anything you’d like it to be (it doesn’t have to be
|
63
|
+
# the shard name, for example), but it must be consistent so Solr
|
64
|
+
# behaves consistently.
|
65
|
+
#
|
66
|
+
# ==== Parameters
|
67
|
+
#
|
68
|
+
# attr_name<Symbol,String>:: Attribute name to call or a string constant
|
69
|
+
#
|
70
|
+
def id_prefix(attr_name = nil, &block)
|
71
|
+
@setup.add_id_prefix(attr_name, &block)
|
72
|
+
end
|
73
|
+
|
58
74
|
# method_missing is used to provide access to typed fields, because
|
59
75
|
# developers should be able to add new Sunspot::Type implementations
|
60
76
|
# dynamically and have them recognized inside the Fields DSL. Like #text,
|
data/lib/sunspot/dsl/fulltext.rb
CHANGED
@@ -176,7 +176,7 @@ module Sunspot
|
|
176
176
|
@query.add_additive_boost_function(factor_or_function)
|
177
177
|
else
|
178
178
|
Sunspot::Util.instance_eval_or_call(
|
179
|
-
Scope.new(@query.
|
179
|
+
Scope.new(@query.add_boost_query(factor_or_function), @setup),
|
180
180
|
&block
|
181
181
|
)
|
182
182
|
end
|
data/lib/sunspot/dsl/group.rb
CHANGED
@@ -59,6 +59,16 @@ module Sunspot
|
|
59
59
|
@group.truncate = true
|
60
60
|
end
|
61
61
|
|
62
|
+
#
|
63
|
+
# The group.ngroups option true return the total number of groups
|
64
|
+
# this is expensive and sometimes you don't need it!
|
65
|
+
# If ngroups is false paginated_collection last_page? and total_pages wont't work.
|
66
|
+
# Defaults to true.
|
67
|
+
#
|
68
|
+
def ngroups(enabled)
|
69
|
+
@group.ngroups = enabled
|
70
|
+
end
|
71
|
+
|
62
72
|
# Specify the order that results should be returned in. This method can
|
63
73
|
# be called multiple times; precedence will be in the order given.
|
64
74
|
#
|
data/lib/sunspot/dsl/scope.rb
CHANGED
@@ -199,25 +199,25 @@ module Sunspot
|
|
199
199
|
|
200
200
|
def add_restriction(negated, *args)
|
201
201
|
case args.first
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
end
|
211
|
-
else # args are instances
|
212
|
-
@scope.add_restriction(
|
213
|
-
negated,
|
214
|
-
IdField.instance,
|
215
|
-
Sunspot::Query::Restriction::AnyOf,
|
216
|
-
args.flatten.map { |instance|
|
217
|
-
Sunspot::Adapters::InstanceAdapter.adapt(instance).index_id }
|
218
|
-
)
|
202
|
+
when String, Symbol
|
203
|
+
raise ArgumentError if args.length > 2
|
204
|
+
field = @setup.field(args[0].to_sym)
|
205
|
+
if args.length > 1
|
206
|
+
value = args[1]
|
207
|
+
@scope.add_shorthand_restriction(negated, field, value)
|
208
|
+
else # NONE
|
209
|
+
DSL::Restriction.new(field, @scope, negated)
|
219
210
|
end
|
211
|
+
else # args are instances
|
212
|
+
@scope.add_restriction(
|
213
|
+
negated,
|
214
|
+
IdField.instance,
|
215
|
+
Sunspot::Query::Restriction::AnyOf,
|
216
|
+
args.flatten.map { |instance|
|
217
|
+
Sunspot::Adapters::InstanceAdapter.adapt(instance).index_id }
|
218
|
+
)
|
220
219
|
end
|
220
|
+
end
|
221
221
|
end
|
222
222
|
end
|
223
223
|
end
|
@@ -9,7 +9,7 @@ module Sunspot
|
|
9
9
|
# See Sunspot.search for usage examples
|
10
10
|
#
|
11
11
|
class StandardQuery < FieldQuery
|
12
|
-
include Paginatable, Adjustable, Spellcheckable
|
12
|
+
include Paginatable, Adjustable, Spellcheckable, Functional
|
13
13
|
|
14
14
|
# Specify a phrase that should be searched as fulltext. Only +text+
|
15
15
|
# fields are searched - see DSL::Fields.text
|
@@ -123,6 +123,34 @@ module Sunspot
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
#
|
127
|
+
# Defines a boost query
|
128
|
+
#
|
129
|
+
# === Examples
|
130
|
+
#
|
131
|
+
# Sunspot.search(Post) do
|
132
|
+
# with(:blog_id, 1)
|
133
|
+
#
|
134
|
+
# boost(10) do
|
135
|
+
# with(:category_id, 2)
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
def boost(factor_or_function, &block)
|
140
|
+
if factor_or_function.is_a?(Sunspot::Query::FunctionQuery)
|
141
|
+
@query.add_boost_function(factor_or_function)
|
142
|
+
else
|
143
|
+
Sunspot::Util.instance_eval_or_call(
|
144
|
+
Scope.new(@query.add_boost_query(factor_or_function), @setup),
|
145
|
+
&block
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def boost_multiplicative(factor_or_function)
|
151
|
+
@query.add_multiplicative_boost_function(factor_or_function)
|
152
|
+
end
|
153
|
+
|
126
154
|
private
|
127
155
|
|
128
156
|
def add_fulltext(keywords, field_names)
|
data/lib/sunspot/dsl.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
%w(spellcheckable fields scope paginatable adjustable field_query
|
2
|
-
standard_query query_facet
|
1
|
+
%w(spellcheckable fields functional scope paginatable adjustable field_query
|
2
|
+
standard_query query_facet fulltext restriction
|
3
3
|
restriction_with_near search more_like_this_query function
|
4
4
|
group field_stats).each do |file|
|
5
5
|
require File.join(File.dirname(__FILE__), 'dsl', file)
|
data/lib/sunspot/field.rb
CHANGED
@@ -195,7 +195,7 @@ module Sunspot
|
|
195
195
|
# Could be of any type
|
196
196
|
#
|
197
197
|
class JoinField < Field #:nodoc:
|
198
|
-
attr_reader :default_boost
|
198
|
+
attr_reader :default_boost
|
199
199
|
|
200
200
|
def initialize(name, type, options = {})
|
201
201
|
@multiple = !!options.delete(:multiple)
|
@@ -213,15 +213,21 @@ module Sunspot
|
|
213
213
|
end
|
214
214
|
|
215
215
|
def from
|
216
|
-
Sunspot::Setup.for(
|
216
|
+
Sunspot::Setup.for(target).field(@join[:from]).indexed_name
|
217
217
|
end
|
218
218
|
|
219
219
|
def to
|
220
220
|
Sunspot::Setup.for(@clazz).field(@join[:to]).indexed_name
|
221
221
|
end
|
222
222
|
|
223
|
-
def local_params
|
224
|
-
|
223
|
+
def local_params(value)
|
224
|
+
query = ["type:\"#{target.name}\""] | Util.Array(value)
|
225
|
+
|
226
|
+
"{!join from=#{from} to=#{to} v='#{query.join(' AND ')}'}"
|
227
|
+
end
|
228
|
+
|
229
|
+
def to_solr_conditional(value)
|
230
|
+
"\"#{value}\""
|
225
231
|
end
|
226
232
|
|
227
233
|
def eql?(field)
|
@@ -229,6 +235,11 @@ module Sunspot
|
|
229
235
|
end
|
230
236
|
|
231
237
|
alias_method :==, :eql?
|
238
|
+
|
239
|
+
def target
|
240
|
+
@target = Util.full_const_get(@target) if @target.is_a?(String)
|
241
|
+
@target
|
242
|
+
end
|
232
243
|
end
|
233
244
|
|
234
245
|
class TypeField #:nodoc:
|
data/lib/sunspot/indexer.rb
CHANGED
@@ -54,9 +54,24 @@ module Sunspot
|
|
54
54
|
# Remove the model from the Solr index by specifying the class and ID
|
55
55
|
#
|
56
56
|
def remove_by_id(class_name, *ids)
|
57
|
+
if class_name.is_a?(String) and class_name.index("!")
|
58
|
+
partition = class_name.rpartition("!")
|
59
|
+
id_prefix = partition[0..1].join
|
60
|
+
class_name = partition[2]
|
61
|
+
else
|
62
|
+
clazz_setup = setup_for_class(Util.full_const_get(class_name))
|
63
|
+
id_prefix = if clazz_setup.id_prefix_defined?
|
64
|
+
if clazz_setup.id_prefix_requires_instance?
|
65
|
+
warn(Sunspot::RemoveByIdNotSupportCompositeIdMessage.call(class_name))
|
66
|
+
else
|
67
|
+
clazz_setup.id_prefix_for_class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
57
72
|
ids.flatten!
|
58
73
|
@connection.delete_by_id(
|
59
|
-
ids.map { |id| Adapters::InstanceAdapter.index_id_for(class_name, id) }
|
74
|
+
ids.map { |id| Adapters::InstanceAdapter.index_id_for("#{id_prefix}#{class_name}", id) }
|
60
75
|
)
|
61
76
|
end
|
62
77
|
|
@@ -147,13 +162,27 @@ module Sunspot
|
|
147
162
|
)
|
148
163
|
end
|
149
164
|
|
150
|
-
def document_for_atomic_update(clazz,
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
165
|
+
def document_for_atomic_update(clazz, key)
|
166
|
+
return unless Adapters::InstanceAdapter.for(clazz)
|
167
|
+
|
168
|
+
clazz_setup = setup_for_class(clazz)
|
169
|
+
id_prefix = if clazz_setup.id_prefix_defined?
|
170
|
+
if clazz_setup.id_prefix_requires_instance?
|
171
|
+
if key.respond_to?(:id)
|
172
|
+
clazz_setup.id_prefix_for(key)
|
173
|
+
else
|
174
|
+
warn(Sunspot::AtomicUpdateRequireInstanceForCompositeIdMessage.call(clazz.name))
|
175
|
+
end
|
176
|
+
else
|
177
|
+
clazz_setup.id_prefix_for_class
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
instance_id = key.respond_to?(:id) ? key.id : key
|
182
|
+
RSolr::Xml::Document.new(
|
183
|
+
id: Adapters::InstanceAdapter.index_id_for("#{id_prefix}#{clazz.name}", instance_id),
|
184
|
+
type: Util.superclasses_for(clazz).map(&:name)
|
185
|
+
)
|
157
186
|
end
|
158
187
|
#
|
159
188
|
# Get the Setup object for the given object's class.
|
@@ -10,7 +10,7 @@ module Sunspot
|
|
10
10
|
#
|
11
11
|
# Assign a new boost query and return it.
|
12
12
|
#
|
13
|
-
def
|
13
|
+
def add_boost_query(factor)
|
14
14
|
@boost_queries << boost_query = BoostQuery.new(factor)
|
15
15
|
boost_query
|
16
16
|
end
|
@@ -19,14 +19,18 @@ module Sunspot
|
|
19
19
|
# Add a boost function
|
20
20
|
#
|
21
21
|
def add_additive_boost_function(function_query)
|
22
|
-
@additive_boost_functions
|
22
|
+
unless @additive_boost_functions.include?(function_query)
|
23
|
+
@additive_boost_functions << function_query
|
24
|
+
end
|
23
25
|
end
|
24
26
|
|
25
27
|
#
|
26
28
|
# Add a multiplicative boost function
|
27
29
|
#
|
28
30
|
def add_multiplicative_boost_function(function_query)
|
29
|
-
@multiplicative_boost_functions
|
31
|
+
unless @multiplicative_boost_functions.include?(function_query)
|
32
|
+
@multiplicative_boost_functions << function_query
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
#
|
@@ -17,6 +17,9 @@ module Sunspot
|
|
17
17
|
params[:sort] = { @options[:sort] => @options[:sort_type]||'desc' } unless @options[:sort].nil?
|
18
18
|
params[:prefix] = @options[:prefix] unless @options[:prefix].nil?
|
19
19
|
params[:offset] = @options[:offset] unless @options[:offset].nil?
|
20
|
+
params[:allBuckets] = @options[:all_buckets] unless @options[:all_buckets].nil?
|
21
|
+
params[:missing] = @options[:missing] unless @options[:missing].nil?
|
22
|
+
params[:method] = @options[:method] unless @options[:method].nil?
|
20
23
|
|
21
24
|
if !@options[:distinct].nil?
|
22
25
|
dist_opts = @options[:distinct]
|
@@ -3,11 +3,30 @@ module Sunspot
|
|
3
3
|
class CompositeFulltext
|
4
4
|
def initialize
|
5
5
|
@components = []
|
6
|
+
@dismax = nil
|
6
7
|
end
|
7
8
|
|
8
9
|
def add_fulltext(keywords)
|
9
|
-
@components << dismax = Dismax.new(keywords)
|
10
|
-
dismax
|
10
|
+
@components << @dismax = Dismax.new(keywords)
|
11
|
+
@dismax
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_boost_query(factor)
|
15
|
+
@dismax ||= Dismax.new("*:*")
|
16
|
+
@components << @dismax unless @components.include?(@dismax)
|
17
|
+
@dismax.add_boost_query(factor)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_boost_function(function)
|
21
|
+
@dismax ||= Dismax.new("*:*")
|
22
|
+
@components << @dismax unless @components.include?(@dismax)
|
23
|
+
@dismax.add_additive_boost_function(function)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_multiplicative_boost_function(function)
|
27
|
+
@dismax ||= Dismax.new("*:*")
|
28
|
+
@components << @dismax unless @components.include?(@dismax)
|
29
|
+
@dismax.add_multiplicative_boost_function(function)
|
11
30
|
end
|
12
31
|
|
13
32
|
def add_join(keywords, target, from, to)
|
@@ -1,24 +1,10 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Query
|
3
|
-
class DateFieldJsonFacet <
|
3
|
+
class DateFieldJsonFacet < RangeJsonFacet
|
4
4
|
|
5
5
|
def initialize(field, options, setup)
|
6
|
-
raise Exception.new('Need to specify a time_range') if options[:time_range].nil?
|
7
|
-
@start = options[:time_range].first
|
8
|
-
@end = options[:time_range].last
|
9
|
-
@gap = "+#{options[:gap] || 86400}SECONDS"
|
10
6
|
super
|
11
|
-
|
12
|
-
|
13
|
-
def field_name_with_local_params
|
14
|
-
params = {}
|
15
|
-
params[:type] = 'range'
|
16
|
-
params[:field] = @field.indexed_name
|
17
|
-
params[:start] = @field.to_indexed(@start)
|
18
|
-
params[:end] = @field.to_indexed(@end)
|
19
|
-
params[:gap] = @gap
|
20
|
-
params.merge!(init_params)
|
21
|
-
{ @field.name => params }
|
7
|
+
@gap = "+#{@gap}#{options[:gap_unit] || 'SECONDS'}"
|
22
8
|
end
|
23
9
|
end
|
24
10
|
end
|
data/lib/sunspot/query/dismax.rb
CHANGED
@@ -28,10 +28,16 @@ module Sunspot
|
|
28
28
|
# The query as Solr parameters
|
29
29
|
#
|
30
30
|
def to_params
|
31
|
-
params = {
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
params = {
|
32
|
+
:q => @keywords,
|
33
|
+
:defType => 'edismax',
|
34
|
+
:fl => '* score'
|
35
|
+
}
|
36
|
+
|
37
|
+
if @fulltext_fields.any?
|
38
|
+
params[:qf] = @fulltext_fields.values.map { |field| field.to_boosted_field }.join(' ')
|
39
|
+
end
|
40
|
+
|
35
41
|
params[:mm] = @minimum_match if @minimum_match
|
36
42
|
params[:ps] = @phrase_slop if @phrase_slop
|
37
43
|
params[:qs] = @query_phrase_slop if @query_phrase_slop
|
@@ -3,18 +3,25 @@ module Sunspot
|
|
3
3
|
#
|
4
4
|
# Abstract class for function queries.
|
5
5
|
#
|
6
|
-
class FunctionQuery
|
6
|
+
class FunctionQuery
|
7
|
+
attr_reader :boost_amount
|
7
8
|
|
8
9
|
def ^(y)
|
9
10
|
@boost_amount = y
|
10
11
|
self
|
11
12
|
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
@boost_amount == other.boost_amount
|
16
|
+
end
|
12
17
|
end
|
13
18
|
|
14
19
|
#
|
15
20
|
# Function query which represents a constant.
|
16
21
|
#
|
17
22
|
class ConstantFunctionQuery < FunctionQuery
|
23
|
+
attr_reader :constant
|
24
|
+
|
18
25
|
def initialize(constant)
|
19
26
|
@constant = constant
|
20
27
|
end
|
@@ -22,12 +29,18 @@ module Sunspot
|
|
22
29
|
def to_s
|
23
30
|
Type.to_literal(@constant) << (@boost_amount ? "^#{@boost_amount}" : "")
|
24
31
|
end
|
32
|
+
|
33
|
+
def ==(other)
|
34
|
+
super and @constant == other.constant
|
35
|
+
end
|
25
36
|
end
|
26
37
|
|
27
38
|
#
|
28
39
|
# Function query which represents a field.
|
29
40
|
#
|
30
41
|
class FieldFunctionQuery < FunctionQuery
|
42
|
+
attr_reader :field
|
43
|
+
|
31
44
|
def initialize(field)
|
32
45
|
@field = field
|
33
46
|
end
|
@@ -35,6 +48,10 @@ module Sunspot
|
|
35
48
|
def to_s
|
36
49
|
"#{Util.escape(@field.indexed_name)}" << (@boost_amount ? "^#{@boost_amount}" : "")
|
37
50
|
end
|
51
|
+
|
52
|
+
def ==(other)
|
53
|
+
super and @field == other.field
|
54
|
+
end
|
38
55
|
end
|
39
56
|
|
40
57
|
#
|
@@ -43,6 +60,8 @@ module Sunspot
|
|
43
60
|
# Arguments are in turn FunctionQuery objects.
|
44
61
|
#
|
45
62
|
class FunctionalFunctionQuery < FunctionQuery
|
63
|
+
attr_reader :function_name, :function_args
|
64
|
+
|
46
65
|
def initialize(function_name, function_args)
|
47
66
|
@function_name, @function_args = function_name, function_args
|
48
67
|
end
|
@@ -51,6 +70,11 @@ module Sunspot
|
|
51
70
|
params = @function_args.map { |arg| arg.to_s }.join(",")
|
52
71
|
"#{@function_name}(#{params})" << (@boost_amount ? "^#{@boost_amount}" : "")
|
53
72
|
end
|
73
|
+
|
74
|
+
def ==(other)
|
75
|
+
super and
|
76
|
+
@function_name == other.function_name and @function_args == other.function_args
|
77
|
+
end
|
54
78
|
end
|
55
79
|
end
|
56
80
|
end
|
data/lib/sunspot/query/group.rb
CHANGED
@@ -4,7 +4,7 @@ module Sunspot
|
|
4
4
|
# A Group groups by the unique values of a given field, or by given queries.
|
5
5
|
#
|
6
6
|
class Group
|
7
|
-
attr_accessor :limit, :truncate
|
7
|
+
attr_accessor :limit, :truncate, :ngroups
|
8
8
|
attr_reader :fields, :queries
|
9
9
|
|
10
10
|
def initialize
|
@@ -30,16 +30,15 @@ module Sunspot
|
|
30
30
|
|
31
31
|
def to_params
|
32
32
|
params = {
|
33
|
-
:group =>
|
34
|
-
:"group.ngroups" =>
|
33
|
+
:group => 'true',
|
34
|
+
:"group.ngroups" => @ngroups.nil? ? 'true' : @ngroups.to_s
|
35
35
|
}
|
36
36
|
|
37
|
-
params.merge!(@sort.to_params(
|
37
|
+
params.merge!(@sort.to_params('group.'))
|
38
38
|
params[:"group.field"] = @fields.map(&:indexed_name) if @fields.any?
|
39
39
|
params[:"group.query"] = @queries.map(&:to_boolean_phrase) if @queries.any?
|
40
40
|
params[:"group.limit"] = @limit if @limit
|
41
41
|
params[:"group.truncate"] = @truncate if @truncate
|
42
|
-
|
43
42
|
params
|
44
43
|
end
|
45
44
|
end
|
data/lib/sunspot/query/join.rb
CHANGED
@@ -42,19 +42,17 @@ module Sunspot
|
|
42
42
|
keywords = escape_quotes(params.delete(:q))
|
43
43
|
options = params.map { |key, value| escape_param(key, value) }.join(' ')
|
44
44
|
q_name = "q#{@target.name}#{self.object_id}"
|
45
|
-
fq_name = "f#{q_name}"
|
46
45
|
|
47
46
|
{
|
48
|
-
:q
|
49
|
-
q_name => "_query_:\"{!edismax #{options}}#{keywords}\""
|
50
|
-
fq_name => "type:#{@target.name}"
|
47
|
+
:q => "_query_:\"{!join from=#{@from} to=#{@to} v=$#{q_name}}\"",
|
48
|
+
q_name => "_query_:\"{!field f=type}#{@target.name}\"+_query_:\"{!edismax #{options}}#{keywords}\""
|
51
49
|
}
|
52
50
|
end
|
53
51
|
|
54
52
|
#
|
55
53
|
# Assign a new boost query and return it.
|
56
54
|
#
|
57
|
-
def
|
55
|
+
def add_boost_query(factor)
|
58
56
|
end
|
59
57
|
|
60
58
|
#
|
@@ -5,10 +5,12 @@ module Sunspot
|
|
5
5
|
SECONDS_IN_DAY = 86400
|
6
6
|
|
7
7
|
def initialize(field, options, setup)
|
8
|
-
|
8
|
+
options[:range] ||= options[:time_range]
|
9
|
+
raise Exception.new("Need to specify a range") if options[:range].nil? && options[:time_range].nil?
|
9
10
|
@start = options[:range].first
|
10
11
|
@end = options[:range].last
|
11
12
|
@gap = options[:gap] || SECONDS_IN_DAY
|
13
|
+
@other = options[:other]
|
12
14
|
super
|
13
15
|
end
|
14
16
|
|
@@ -19,7 +21,8 @@ module Sunspot
|
|
19
21
|
field: @field.indexed_name,
|
20
22
|
start: @field.to_indexed(@start),
|
21
23
|
end: @field.to_indexed(@end),
|
22
|
-
gap: @gap
|
24
|
+
gap: @gap,
|
25
|
+
other: @other
|
23
26
|
}.merge!(init_params)
|
24
27
|
}
|
25
28
|
end
|