sunspot 2.5.0 → 2.7.1
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/lib/sunspot/adapters.rb +14 -3
- data/lib/sunspot/data_extractor.rb +1 -1
- data/lib/sunspot/dsl/fulltext.rb +1 -1
- data/lib/sunspot/dsl/standard_query.rb +29 -1
- data/lib/sunspot/dsl.rb +2 -2
- data/lib/sunspot/field.rb +21 -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/join.rb +1 -1
- data/lib/sunspot/query/range_json_facet.rb +5 -2
- data/lib/sunspot/query/restriction.rb +16 -10
- data/lib/sunspot/query/standard_query.rb +12 -0
- data/lib/sunspot/search/field_json_facet.rb +14 -3
- data/lib/sunspot/session.rb +7 -5
- data/lib/sunspot/setup.rb +38 -0
- data/lib/sunspot/util.rb +24 -21
- data/lib/sunspot/version.rb +1 -1
- data/lib/sunspot.rb +9 -1
- data/spec/api/binding_spec.rb +15 -0
- data/spec/api/indexer/attributes_spec.rb +1 -1
- data/spec/api/indexer/removal_spec.rb +87 -0
- data/spec/api/query/connective_boost_examples.rb +85 -0
- data/spec/api/query/geo_examples.rb +1 -1
- data/spec/api/query/join_spec.rb +2 -2
- data/spec/api/query/standard_spec.rb +10 -0
- data/spec/api/query/types_spec.rb +2 -2
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +1 -1
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +9 -5
- data/spec/api/session_spec.rb +1 -1
- data/spec/api/setup_spec.rb +99 -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/join_spec.rb +22 -3
- data/spec/integration/scoped_search_spec.rb +78 -0
- data/spec/mocks/comment.rb +1 -1
- data/spec/mocks/connection.rb +6 -0
- data/spec/mocks/photo.rb +11 -7
- data/spec/mocks/post.rb +35 -1
- data/sunspot.gemspec +4 -6
- metadata +33 -15
@@ -1,6 +1,79 @@
|
|
1
1
|
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
2
|
|
3
|
-
|
3
|
+
shared_examples 'atomic update with instance as key' do
|
4
|
+
it 'updates record' do
|
5
|
+
post = clazz.new(title: 'A Title', featured: true)
|
6
|
+
Sunspot.index!(post)
|
7
|
+
|
8
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
9
|
+
|
10
|
+
Sunspot.atomic_update!(clazz, post => { title: 'A New Title' })
|
11
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A New Title', featured: true)
|
12
|
+
|
13
|
+
Sunspot.atomic_update!(clazz, post => { featured: false })
|
14
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A New Title', featured: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not print warning' do
|
18
|
+
post = clazz.new(title: 'A Title', featured: true)
|
19
|
+
Sunspot.index!(post)
|
20
|
+
|
21
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
22
|
+
|
23
|
+
expect do
|
24
|
+
Sunspot.atomic_update!(clazz, post => { title: 'A New Title' })
|
25
|
+
end.to_not output(Sunspot::AtomicUpdateRequireInstanceForCompositeIdMessage.call(clazz)).to_stderr
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'does not create duplicate document' do
|
29
|
+
post = clazz.new(title: 'A Title', featured: true)
|
30
|
+
Sunspot.index!(post)
|
31
|
+
|
32
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
33
|
+
|
34
|
+
Sunspot.atomic_update!(clazz, post => { title: 'A New Title' })
|
35
|
+
hit = find_indexed_post_with_prefix_id(post, nil)
|
36
|
+
expect(hit).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
shared_examples 'atomic update with id as key' do
|
41
|
+
it 'does not update record' do
|
42
|
+
post = clazz.new(title: 'A Title', featured: true)
|
43
|
+
Sunspot.index!(post)
|
44
|
+
|
45
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
46
|
+
|
47
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
48
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A Title', featured: true)
|
49
|
+
|
50
|
+
Sunspot.atomic_update!(clazz, post.id => { featured: false })
|
51
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A Title', featured: true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'prints warning' do
|
55
|
+
post = clazz.new(title: 'A Title', featured: true)
|
56
|
+
Sunspot.index!(post)
|
57
|
+
|
58
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
59
|
+
|
60
|
+
expect do
|
61
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
62
|
+
end.to output(Sunspot::AtomicUpdateRequireInstanceForCompositeIdMessage.call(clazz) + "\n").to_stderr
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'creates duplicate document that have only fields provided for update' do
|
66
|
+
post = clazz.new(title: 'A Title', featured: true)
|
67
|
+
Sunspot.index!(post)
|
68
|
+
|
69
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
70
|
+
|
71
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
72
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, nil), title: 'A New Title', featured: nil)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'Atomic Update feature' do
|
4
77
|
before :all do
|
5
78
|
Sunspot.remove_all
|
6
79
|
end
|
@@ -18,10 +91,27 @@ describe 'atomic updates' do
|
|
18
91
|
hit
|
19
92
|
end
|
20
93
|
|
21
|
-
|
94
|
+
def find_and_validate_indexed_post_with_prefix_id(post, id_prefix)
|
95
|
+
hit = find_indexed_post_with_prefix_id(post, id_prefix_value(post, id_prefix))
|
96
|
+
expect(hit).not_to be_nil
|
97
|
+
hit
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_indexed_post_with_prefix_id(post, id_prefix)
|
101
|
+
Sunspot.search(post.class).hits.find { |h| h.primary_key.to_i == post.id && h.id_prefix == id_prefix }
|
102
|
+
end
|
103
|
+
|
104
|
+
def id_prefix_value(post, id_prefix)
|
105
|
+
return unless id_prefix
|
106
|
+
return id_prefix if id_prefix.is_a?(String)
|
107
|
+
|
108
|
+
id_prefix.call(post)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'updates single record fields one by one' do
|
22
112
|
post = Post.new(title: 'A Title', featured: true)
|
23
113
|
Sunspot.index!(post)
|
24
|
-
|
114
|
+
|
25
115
|
validate_hit(find_indexed_post(post.id), title: post.title, featured: post.featured)
|
26
116
|
|
27
117
|
Sunspot.atomic_update!(Post, post.id => {title: 'A New Title'})
|
@@ -31,7 +121,7 @@ describe 'atomic updates' do
|
|
31
121
|
validate_hit(find_indexed_post(post.id), title: 'A New Title', featured: false)
|
32
122
|
end
|
33
123
|
|
34
|
-
it '
|
124
|
+
it 'updates fields for multiple records' do
|
35
125
|
post1 = Post.new(title: 'A First Title', featured: true)
|
36
126
|
post2 = Post.new(title: 'A Second Title', featured: false)
|
37
127
|
Sunspot.index!(post1, post2)
|
@@ -44,7 +134,7 @@ describe 'atomic updates' do
|
|
44
134
|
validate_hit(find_indexed_post(post2.id), title: 'A Second Title', featured: true)
|
45
135
|
end
|
46
136
|
|
47
|
-
it '
|
137
|
+
it 'clears field value properly' do
|
48
138
|
post = Post.new(title: 'A Title', tags: %w(tag1 tag2), featured: true)
|
49
139
|
Sunspot.index!(post)
|
50
140
|
validate_hit(find_indexed_post(post.id), title: post.title, tag_list: post.tags, featured: true)
|
@@ -55,4 +145,78 @@ describe 'atomic updates' do
|
|
55
145
|
Sunspot.atomic_update!(Post, post.id => {featured: nil})
|
56
146
|
validate_hit(find_indexed_post(post.id), title: post.title, tag_list: nil, featured: nil)
|
57
147
|
end
|
148
|
+
|
149
|
+
context 'when `id_prefix` is defined on model' do
|
150
|
+
context 'as Proc' do
|
151
|
+
let(:clazz) { PostWithProcPrefixId }
|
152
|
+
let(:id_prefix) { lambda { |post| "USERDATA-#{post.id}!" } }
|
153
|
+
|
154
|
+
context 'and instance passed as key' do
|
155
|
+
include_examples 'atomic update with instance as key'
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'and id passed as key' do
|
159
|
+
include_examples 'atomic update with id as key'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'as Symbol' do
|
164
|
+
let(:clazz) { PostWithSymbolPrefixId }
|
165
|
+
let(:id_prefix) { lambda { |post| "#{post.title}!" } }
|
166
|
+
|
167
|
+
context 'and instance passed as key' do
|
168
|
+
include_examples 'atomic update with instance as key'
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'and id passed as key' do
|
172
|
+
include_examples 'atomic update with id as key'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'as String' do
|
177
|
+
let(:clazz) { PostWithStringPrefixId }
|
178
|
+
let(:id_prefix) { 'USERDATA!' }
|
179
|
+
|
180
|
+
context 'and instance passed as key' do
|
181
|
+
include_examples 'atomic update with instance as key'
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'and id passed as key' do
|
185
|
+
it 'updates record' do
|
186
|
+
post = clazz.new(title: 'A Title', featured: true)
|
187
|
+
Sunspot.index!(post)
|
188
|
+
|
189
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
190
|
+
|
191
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
192
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A New Title', featured: true)
|
193
|
+
|
194
|
+
Sunspot.atomic_update!(clazz, post.id => { featured: false })
|
195
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: 'A New Title', featured: false)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'does not print warning' do
|
199
|
+
post = clazz.new(title: 'A Title', featured: true)
|
200
|
+
Sunspot.index!(post)
|
201
|
+
|
202
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
203
|
+
|
204
|
+
expect do
|
205
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
206
|
+
end.to_not output(Sunspot::AtomicUpdateRequireInstanceForCompositeIdMessage.call(clazz) + "\n").to_stderr
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'does not create duplicate document' do
|
210
|
+
post = clazz.new(title: 'A Title', featured: true)
|
211
|
+
Sunspot.index!(post)
|
212
|
+
|
213
|
+
validate_hit(find_and_validate_indexed_post_with_prefix_id(post, id_prefix), title: post.title, featured: post.featured)
|
214
|
+
|
215
|
+
Sunspot.atomic_update!(clazz, post.id => { title: 'A New Title' })
|
216
|
+
hit = find_indexed_post_with_prefix_id(post, nil)
|
217
|
+
expect(hit).to be_nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
58
222
|
end
|
@@ -84,7 +84,7 @@ describe 'search faceting' do
|
|
84
84
|
end
|
85
85
|
expect(search.facet(:title).rows.map { |row| row.value }).to include('zero')
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it 'should return facet rows from an offset' do
|
89
89
|
search = Sunspot.search(Post) do
|
90
90
|
facet :title, :offset => 3
|
@@ -214,6 +214,15 @@ describe 'search faceting' do
|
|
214
214
|
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
|
215
215
|
end
|
216
216
|
|
217
|
+
it 'should include allBuckets and missing' do
|
218
|
+
search = Sunspot.search(Post) do
|
219
|
+
with :blog_id, 1
|
220
|
+
json_facet :title, all_buckets: true, missing: true
|
221
|
+
end
|
222
|
+
expect(search.facet(:title).other_count('allBuckets')).to eq(10)
|
223
|
+
expect(search.facet(:title).other_count('missing')).to eq(1)
|
224
|
+
end
|
225
|
+
|
217
226
|
it 'should limit facet values by prefix' do
|
218
227
|
search = Sunspot.search(Post) do
|
219
228
|
with :blog_id, 1
|
@@ -221,7 +230,64 @@ describe 'search faceting' do
|
|
221
230
|
end
|
222
231
|
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
|
223
232
|
end
|
233
|
+
end
|
224
234
|
|
235
|
+
context 'date or time json facet' do
|
236
|
+
before :all do
|
237
|
+
Sunspot.remove_all
|
238
|
+
posts = [
|
239
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 8, 20)),
|
240
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 7, 20)),
|
241
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 6, 20)),
|
242
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 6, 15)),
|
243
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 5, 20)),
|
244
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 4, 20)),
|
245
|
+
Post.new(title: 'dt test', blog_id: 1, published_at: Time.new(2020, 3, 20))
|
246
|
+
]
|
247
|
+
posts.each { |p| Sunspot.index(p) }
|
248
|
+
Sunspot.commit
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'facets properly with the range specified as time_range' do
|
252
|
+
time_range = [Time.new(2020, 4, 1), Time.new(2020, 7, 31)]
|
253
|
+
search = Sunspot.search(Post) do
|
254
|
+
with :blog_id, 1
|
255
|
+
json_facet :published_at, time_range: time_range, gap: 1, gap_unit: 'MONTHS'
|
256
|
+
end
|
257
|
+
expected_rows = [
|
258
|
+
{ count: 1, value: Time.new(2020, 4, 1).utc.iso8601 },
|
259
|
+
{ count: 1, value: Time.new(2020, 5, 1).utc.iso8601 },
|
260
|
+
{ count: 2, value: Time.new(2020, 6, 1).utc.iso8601 },
|
261
|
+
{ count: 1, value: Time.new(2020, 7, 1).utc.iso8601 }
|
262
|
+
]
|
263
|
+
expect(search.facet(:published_at).rows.map { |row| { count: row.count, value: row.value } }).to eq(expected_rows)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should use custom gap parameters if provided' do
|
267
|
+
time_range = [Time.new(2020, 4, 1), Time.new(2020, 7, 31)]
|
268
|
+
search = Sunspot.search(Post) do
|
269
|
+
with :blog_id, 1
|
270
|
+
json_facet :published_at, range: time_range, gap: 1, gap_unit: 'MONTHS'
|
271
|
+
end
|
272
|
+
expected_rows = [
|
273
|
+
{ count: 1, value: Time.new(2020, 4, 1).utc.iso8601 },
|
274
|
+
{ count: 1, value: Time.new(2020, 5, 1).utc.iso8601 },
|
275
|
+
{ count: 2, value: Time.new(2020, 6, 1).utc.iso8601 },
|
276
|
+
{ count: 1, value: Time.new(2020, 7, 1).utc.iso8601 }
|
277
|
+
]
|
278
|
+
expect(search.facet(:published_at).rows.map { |row| { count: row.count, value: row.value } }).to eq(expected_rows)
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'should support computing other statistics' do
|
282
|
+
time_range = [Time.new(2020, 5, 1), Time.new(2020, 7, 1)]
|
283
|
+
search = Sunspot.search(Post) do
|
284
|
+
with :blog_id, 1
|
285
|
+
json_facet :published_at, range: time_range, gap: 1, gap_unit: 'MONTHS', other: 'all'
|
286
|
+
end
|
287
|
+
expect(search.facet(:published_at).other_count('before')).to eq(2)
|
288
|
+
expect(search.facet(:published_at).other_count('after')).to eq(2)
|
289
|
+
expect(search.facet(:published_at).other_count('between')).to eq(3)
|
290
|
+
end
|
225
291
|
end
|
226
292
|
|
227
293
|
context 'nested json facet' do
|
@@ -237,7 +303,7 @@ describe 'search faceting' do
|
|
237
303
|
end
|
238
304
|
|
239
305
|
0.upto(9) { |i| Sunspot.index(Post.new(:title => 'zero', :author_name => "another#{i}", :blog_id => 1)) }
|
240
|
-
|
306
|
+
|
241
307
|
Sunspot.commit
|
242
308
|
end
|
243
309
|
|
@@ -459,38 +525,6 @@ describe 'search faceting' do
|
|
459
525
|
expect(search.facet(:published_at).rows.last.value).to eq((time + 60*60*24)..(time + 60*60*24*2))
|
460
526
|
expect(search.facet(:published_at).rows.last.count).to eq(1)
|
461
527
|
end
|
462
|
-
|
463
|
-
it 'json facet should return time ranges' do
|
464
|
-
days_diff = 15
|
465
|
-
time_from = Time.utc(2009, 7, 8)
|
466
|
-
time_to = Time.utc(2009, 7, 8 + days_diff)
|
467
|
-
search = Sunspot.search(Post) do
|
468
|
-
json_facet(
|
469
|
-
:published_at,
|
470
|
-
:time_range => time_from..time_to
|
471
|
-
)
|
472
|
-
end
|
473
|
-
|
474
|
-
expect(search.facet(:published_at).rows.size).to eq(days_diff)
|
475
|
-
expect(search.facet(:published_at).rows[0].count).to eq(2)
|
476
|
-
expect(search.facet(:published_at).rows[1].count).to eq(1)
|
477
|
-
end
|
478
|
-
|
479
|
-
it 'json facet should return time ranges with custom gap' do
|
480
|
-
days_diff = 10
|
481
|
-
time_from = Time.utc(2009, 7, 8)
|
482
|
-
time_to = Time.utc(2009, 7, 8 + days_diff)
|
483
|
-
search = Sunspot.search(Post) do
|
484
|
-
json_facet(
|
485
|
-
:published_at,
|
486
|
-
:time_range => time_from..time_to,
|
487
|
-
gap: 60*60*24*2
|
488
|
-
)
|
489
|
-
end
|
490
|
-
expect(search.facet(:published_at).rows.size).to eq(days_diff / 2)
|
491
|
-
expect(search.facet(:published_at).rows[0].count).to eq(3)
|
492
|
-
end
|
493
|
-
|
494
528
|
end
|
495
529
|
|
496
530
|
context 'class facets' do
|
@@ -8,9 +8,9 @@ describe "searching by joined fields" do
|
|
8
8
|
@container2 = PhotoContainer.new(:id => 2).tap { |c| allow(c).to receive(:id).and_return(2) }
|
9
9
|
@container3 = PhotoContainer.new(:id => 3).tap { |c| allow(c).to receive(:id).and_return(3) }
|
10
10
|
|
11
|
-
@picture = Picture.new(:photo_container_id => @container1.id, :description => "one")
|
12
|
-
@photo1 = Photo.new(:photo_container_id => @container1.id, :description => "two")
|
13
|
-
@photo2 = Photo.new(:photo_container_id => @container2.id, :description => "three")
|
11
|
+
@picture = Picture.new(:photo_container_id => @container1.id, :description => "one", :published => true)
|
12
|
+
@photo1 = Photo.new(:photo_container_id => @container1.id, :description => "two", :published => true)
|
13
|
+
@photo2 = Photo.new(:photo_container_id => @container2.id, :description => "three", :published => false)
|
14
14
|
|
15
15
|
Sunspot.index!(@container1, @container2, @photo1, @photo2, @picture)
|
16
16
|
end
|
@@ -42,4 +42,23 @@ describe "searching by joined fields" do
|
|
42
42
|
expect(results).to eq res
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
46
|
+
it "matches by joined fields when using filter queries" do
|
47
|
+
{
|
48
|
+
:photo_published => [
|
49
|
+
[true, [@container1]],
|
50
|
+
[false, [@container2]]
|
51
|
+
],
|
52
|
+
:picture_published => [
|
53
|
+
[true, [@container1]],
|
54
|
+
[false, []]
|
55
|
+
]
|
56
|
+
}.each do |key, data|
|
57
|
+
data.each do |(value, res)|
|
58
|
+
results = Sunspot.search(PhotoContainer) { with(key, value) }.results
|
59
|
+
|
60
|
+
expect(results).to eq res
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
45
64
|
end
|
@@ -538,4 +538,82 @@ describe 'scoped_search' do
|
|
538
538
|
expect(search.results.first).to eq(@p1)
|
539
539
|
end
|
540
540
|
end
|
541
|
+
|
542
|
+
describe 'boosting' do
|
543
|
+
before :all do
|
544
|
+
Sunspot.remove_all
|
545
|
+
@p1 = Post.new(:title => 'Post', :body => 'Lorem', :blog_id => 1, :category_ids => [3], :ratings_average => 30)
|
546
|
+
@p2 = Post.new(:title => 'Post', :body => 'Ipsum', :blog_id => 2, :category_ids => [2], :ratings_average => 60)
|
547
|
+
@p3 = Post.new(:title => 'Post', :body => 'Dolor', :blog_id => 3, :category_ids => [1], :ratings_average => 90)
|
548
|
+
Sunspot.index([@p1, @p2, @p3])
|
549
|
+
Sunspot.commit
|
550
|
+
end
|
551
|
+
|
552
|
+
it 'without boost should returns post in default order' do
|
553
|
+
search = Sunspot.search(Post) {}
|
554
|
+
|
555
|
+
expect(search.results[0]).to eq(@p1)
|
556
|
+
expect(search.results[1]).to eq(@p2)
|
557
|
+
expect(search.results[2]).to eq(@p3)
|
558
|
+
end
|
559
|
+
|
560
|
+
it 'should apply boost function' do
|
561
|
+
search = Sunspot.search(Post) do
|
562
|
+
boost(function() { field(:average_rating) })
|
563
|
+
end
|
564
|
+
|
565
|
+
expect(search.results[0]).to eq(@p3)
|
566
|
+
expect(search.results[1]).to eq(@p2)
|
567
|
+
expect(search.results[2]).to eq(@p1)
|
568
|
+
end
|
569
|
+
|
570
|
+
it 'should apply multilicative boost function' do
|
571
|
+
search = Sunspot.search(Post) do
|
572
|
+
boost_multiplicative(function() { field(:average_rating) })
|
573
|
+
end
|
574
|
+
|
575
|
+
expect(search.results[0]).to eq(@p3)
|
576
|
+
expect(search.results[1]).to eq(@p2)
|
577
|
+
expect(search.results[2]).to eq(@p1)
|
578
|
+
end
|
579
|
+
|
580
|
+
it 'should apply boost query' do
|
581
|
+
search = Sunspot.search(Post) do
|
582
|
+
boost(5) do
|
583
|
+
with(:blog_id, 1)
|
584
|
+
end
|
585
|
+
|
586
|
+
boost(10) do
|
587
|
+
with(:blog_id, 3)
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
expect(search.results[0]).to eq(@p3)
|
592
|
+
expect(search.results[1]).to eq(@p1)
|
593
|
+
expect(search.results[2]).to eq(@p2)
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'should work properly when combined with fulltext' do
|
597
|
+
search = Sunspot.search(Post) do
|
598
|
+
fulltext('Post Ipsum') do
|
599
|
+
boost_fields :body => 0.2
|
600
|
+
minimum_match 1
|
601
|
+
end
|
602
|
+
|
603
|
+
boost(0.9) do
|
604
|
+
with(:blog_id, 1)
|
605
|
+
end
|
606
|
+
|
607
|
+
boost(function() { div(field(:average_rating), 100) })
|
608
|
+
|
609
|
+
fulltext('Post') do
|
610
|
+
minimum_match 1
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
expect(search.results[0]).to eq(@p2)
|
615
|
+
expect(search.results[1]).to eq(@p3)
|
616
|
+
expect(search.results[2]).to eq(@p1)
|
617
|
+
end
|
618
|
+
end
|
541
619
|
end
|
data/spec/mocks/comment.rb
CHANGED
data/spec/mocks/connection.rb
CHANGED
data/spec/mocks/photo.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Photo < MockRecord
|
2
|
-
attr_accessor :caption, :description, :lat, :lng, :size, :average_rating, :created_at, :post_id, :photo_container_id
|
2
|
+
attr_accessor :caption, :description, :lat, :lng, :size, :average_rating, :created_at, :post_id, :photo_container_id, :published
|
3
3
|
end
|
4
4
|
|
5
5
|
Sunspot.setup(Photo) do
|
@@ -7,6 +7,7 @@ Sunspot.setup(Photo) do
|
|
7
7
|
text :description
|
8
8
|
string :caption
|
9
9
|
integer :photo_container_id
|
10
|
+
boolean :published
|
10
11
|
boost 0.75
|
11
12
|
integer :size, :trie => true
|
12
13
|
float :average_rating, :trie => true
|
@@ -14,12 +15,13 @@ Sunspot.setup(Photo) do
|
|
14
15
|
end
|
15
16
|
|
16
17
|
class Picture < MockRecord
|
17
|
-
attr_accessor :description, :photo_container_id
|
18
|
+
attr_accessor :description, :photo_container_id, :published
|
18
19
|
end
|
19
20
|
|
20
21
|
Sunspot.setup(Picture) do
|
21
22
|
text :description
|
22
23
|
integer :photo_container_id
|
24
|
+
boolean :published
|
23
25
|
end
|
24
26
|
|
25
27
|
class PhotoContainer < MockRecord
|
@@ -34,9 +36,11 @@ Sunspot.setup(PhotoContainer) do
|
|
34
36
|
integer :id
|
35
37
|
text :description, :default_boost => 1.2
|
36
38
|
|
37
|
-
join(:caption, :target => Photo, :type => :string, :join => { :from => :photo_container_id, :to => :id })
|
38
|
-
join(:photo_rating, :target => Photo, :type => :trie_float, :join => { :from => :photo_container_id, :to => :id }, :as => 'average_rating_ft')
|
39
|
-
join(:caption, :target => Photo, :type => :text, :join => { :from => :photo_container_id, :to => :id })
|
40
|
-
join(:description, :target => Photo, :type => :text, :join => { :from => :photo_container_id, :to => :id }, :prefix => "photo")
|
41
|
-
join(:
|
39
|
+
join(:caption, :target => 'Photo', :type => :string, :join => { :from => :photo_container_id, :to => :id })
|
40
|
+
join(:photo_rating, :target => 'Photo', :type => :trie_float, :join => { :from => :photo_container_id, :to => :id }, :as => 'average_rating_ft')
|
41
|
+
join(:caption, :target => 'Photo', :type => :text, :join => { :from => :photo_container_id, :to => :id })
|
42
|
+
join(:description, :target => 'Photo', :type => :text, :join => { :from => :photo_container_id, :to => :id }, :prefix => "photo")
|
43
|
+
join(:published, :target => 'Photo', :type => :boolean, :join => { :from => :photo_container_id, :to => :id }, :prefix => "photo")
|
44
|
+
join(:description, :target => 'Picture', :type => :text, :join => { :from => :photo_container_id, :to => :id }, :prefix => "picture")
|
45
|
+
join(:published, :target => 'Picture', :type => :boolean, :join => { :from => :photo_container_id, :to => :id }, :prefix => "picture")
|
42
46
|
end
|
data/spec/mocks/post.rb
CHANGED
@@ -37,7 +37,7 @@ end
|
|
37
37
|
|
38
38
|
Sunspot.setup(Post) do
|
39
39
|
text :title, :boost => 2
|
40
|
-
text :text_array
|
40
|
+
text :text_array do
|
41
41
|
[title, title]
|
42
42
|
end
|
43
43
|
text :body, :stored => true, :more_like_this => true
|
@@ -99,3 +99,37 @@ end
|
|
99
99
|
class PhotoPost < Post
|
100
100
|
end
|
101
101
|
|
102
|
+
class PostWithProcPrefixId < Post
|
103
|
+
end
|
104
|
+
|
105
|
+
Sunspot.setup(PostWithProcPrefixId) do
|
106
|
+
id_prefix { "USERDATA-#{id}!" }
|
107
|
+
string :title, :stored => true
|
108
|
+
boolean :featured, :using => :featured?, :stored => true
|
109
|
+
end
|
110
|
+
|
111
|
+
class PostWithSymbolPrefixId < Post
|
112
|
+
end
|
113
|
+
|
114
|
+
Sunspot.setup(PostWithSymbolPrefixId) do
|
115
|
+
id_prefix :title
|
116
|
+
string :title, :stored => true
|
117
|
+
boolean :featured, :using => :featured?, :stored => true
|
118
|
+
end
|
119
|
+
|
120
|
+
class PostWithStringPrefixId < Post
|
121
|
+
end
|
122
|
+
|
123
|
+
Sunspot.setup(PostWithStringPrefixId) do
|
124
|
+
id_prefix 'USERDATA!'
|
125
|
+
string :title, :stored => true
|
126
|
+
boolean :featured, :using => :featured?, :stored => true
|
127
|
+
end
|
128
|
+
|
129
|
+
class PostWithoutPrefixId < Post
|
130
|
+
end
|
131
|
+
|
132
|
+
Sunspot.setup(PostWithoutPrefixId) do
|
133
|
+
string :title, :stored => true
|
134
|
+
boolean :featured, :using => :featured?, :stored => true
|
135
|
+
end
|
data/sunspot.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
'Dylan Vaughn', 'Brian Durand', 'Sam Granieri', 'Nick Zadrozny', 'Jason Ronallo', 'Ryan Wallace', 'Nicholas Jakobsen',
|
12
12
|
'Bragadeesh J', 'Ethiraj Srinivasan']
|
13
13
|
s.email = ["mat@patch.com"]
|
14
|
-
s.homepage = "
|
14
|
+
s.homepage = "https://sunspot.github.io"
|
15
15
|
s.summary = 'Library for expressive, powerful interaction with the Solr search engine'
|
16
16
|
s.license = 'MIT'
|
17
17
|
s.description = <<-TEXT
|
@@ -20,8 +20,6 @@ Gem::Specification.new do |s|
|
|
20
20
|
can be performed without hand-writing any boolean queries or building Solr parameters by hand.
|
21
21
|
TEXT
|
22
22
|
|
23
|
-
s.rubyforge_project = "sunspot"
|
24
|
-
|
25
23
|
s.files = `git ls-files`.split("\n")
|
26
24
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
27
25
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
@@ -29,10 +27,10 @@ Gem::Specification.new do |s|
|
|
29
27
|
|
30
28
|
s.add_dependency 'rsolr', '>= 1.1.1', '< 3'
|
31
29
|
s.add_dependency 'pr_geohash', '~>1.0'
|
32
|
-
|
33
|
-
s.add_development_dependency 'rake', '
|
30
|
+
s.add_dependency 'bigdecimal'
|
31
|
+
s.add_development_dependency 'rake', '~> 13.2'
|
34
32
|
s.add_development_dependency 'rspec', '~> 3.7'
|
35
|
-
s.add_development_dependency 'appraisal', '2.
|
33
|
+
s.add_development_dependency 'appraisal', '~> 2.5'
|
36
34
|
|
37
35
|
s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
|
38
36
|
'--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation' <<
|