sunspot 2.0.0 → 2.5.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 +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
|
@@ -3,28 +3,28 @@ shared_examples_for 'fulltext query' do
|
|
|
3
3
|
search do
|
|
4
4
|
keywords 'keyword search'
|
|
5
5
|
end
|
|
6
|
-
connection.
|
|
6
|
+
expect(connection).to have_last_search_with(:q => 'keyword search')
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it 'ignores keywords if empty' do
|
|
10
10
|
search do
|
|
11
11
|
keywords ''
|
|
12
12
|
end
|
|
13
|
-
connection.
|
|
13
|
+
expect(connection).not_to have_last_search_with(:defType => 'edismax')
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it 'ignores keywords if nil' do
|
|
17
17
|
search do
|
|
18
18
|
keywords nil
|
|
19
19
|
end
|
|
20
|
-
connection.
|
|
20
|
+
expect(connection).not_to have_last_search_with(:defType => 'edismax')
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
it 'ignores keywords with only whitespace' do
|
|
24
24
|
search do
|
|
25
25
|
keywords " \t"
|
|
26
26
|
end
|
|
27
|
-
connection.
|
|
27
|
+
expect(connection).not_to have_last_search_with(:defType => 'edismax')
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it 'gracefully ignores keywords block if keywords ignored' do
|
|
@@ -37,14 +37,14 @@ shared_examples_for 'fulltext query' do
|
|
|
37
37
|
search do
|
|
38
38
|
keywords 'keyword search'
|
|
39
39
|
end
|
|
40
|
-
connection.
|
|
40
|
+
expect(connection).to have_last_search_with(:defType => 'edismax')
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
it 'searches types in filter query if keywords used' do
|
|
44
44
|
search do
|
|
45
45
|
keywords 'keyword search'
|
|
46
46
|
end
|
|
47
|
-
connection.
|
|
47
|
+
expect(connection).to have_last_search_with(:fq => ['type:Post'])
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
describe 'with multiple keyword components' do
|
|
@@ -56,20 +56,23 @@ shared_examples_for 'fulltext query' do
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
it 'puts specified keywords in subquery' do
|
|
59
|
-
subqueries(:q).map { |subquery| subquery[:v] }.
|
|
59
|
+
expect(subqueries(:q).map { |subquery| subquery[:v] }).to eq(
|
|
60
60
|
['first search', 'second search']
|
|
61
|
+
)
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
it 'puts specified dismax parameters in subquery' do
|
|
64
|
-
subqueries(:q).first[:qf].
|
|
65
|
+
expect(subqueries(:q).first[:qf]).to eq('title_text')
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
it 'puts default dismax parameters in subquery' do
|
|
68
|
-
subqueries(:q).last[:qf].split(' ').sort.
|
|
69
|
+
expect(subqueries(:q).last[:qf].split(' ').sort).to(
|
|
70
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text))
|
|
71
|
+
)
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
it 'puts field list in main query' do
|
|
72
|
-
connection.
|
|
75
|
+
expect(connection).to have_last_search_with(:fl => '* score')
|
|
73
76
|
end
|
|
74
77
|
end
|
|
75
78
|
|
|
@@ -77,21 +80,25 @@ shared_examples_for 'fulltext query' do
|
|
|
77
80
|
search = search do
|
|
78
81
|
keywords 'keyword search'
|
|
79
82
|
end
|
|
80
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
83
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
|
84
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text))
|
|
85
|
+
)
|
|
81
86
|
end
|
|
82
87
|
|
|
83
88
|
it 'searches both stored and unstored text fields' do
|
|
84
89
|
search Post, Namespaced::Comment do
|
|
85
90
|
keywords 'keyword search'
|
|
86
91
|
end
|
|
87
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
92
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
|
93
|
+
eq(%w(author_name_text backwards_title_text body_text body_textsv tags_textv text_array_text title_text))
|
|
94
|
+
)
|
|
88
95
|
end
|
|
89
96
|
|
|
90
97
|
it 'searches only specified text fields when specified' do
|
|
91
98
|
search do
|
|
92
99
|
keywords 'keyword search', :fields => [:title, :body]
|
|
93
100
|
end
|
|
94
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
101
|
+
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_textsv title_text))
|
|
95
102
|
end
|
|
96
103
|
|
|
97
104
|
it 'excludes text fields when instructed' do
|
|
@@ -100,7 +107,7 @@ shared_examples_for 'fulltext query' do
|
|
|
100
107
|
exclude_fields :backwards_title, :body_mlt
|
|
101
108
|
end
|
|
102
109
|
end
|
|
103
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
110
|
+
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_textsv tags_textv text_array_text title_text))
|
|
104
111
|
end
|
|
105
112
|
|
|
106
113
|
it 'assigns boost to fields when specified' do
|
|
@@ -109,7 +116,7 @@ shared_examples_for 'fulltext query' do
|
|
|
109
116
|
fields :title => 2.0, :body => 0.75
|
|
110
117
|
end
|
|
111
118
|
end
|
|
112
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
119
|
+
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_textsv^0.75 title_text^2.0))
|
|
113
120
|
end
|
|
114
121
|
|
|
115
122
|
it 'allows assignment of boosted and unboosted fields' do
|
|
@@ -124,19 +131,19 @@ shared_examples_for 'fulltext query' do
|
|
|
124
131
|
search Post, Namespaced::Comment do
|
|
125
132
|
keywords 'keyword search', :fields => [:body]
|
|
126
133
|
end
|
|
127
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
134
|
+
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_text body_textsv))
|
|
128
135
|
end
|
|
129
136
|
|
|
130
137
|
it 'requests score when keywords used' do
|
|
131
138
|
search do
|
|
132
139
|
keywords 'keyword search'
|
|
133
140
|
end
|
|
134
|
-
connection.
|
|
141
|
+
expect(connection).to have_last_search_with(:fl => '* score')
|
|
135
142
|
end
|
|
136
143
|
|
|
137
144
|
it 'does not request score when keywords not used' do
|
|
138
145
|
search Post
|
|
139
|
-
connection.
|
|
146
|
+
expect(connection).not_to have_last_search_with(:fl)
|
|
140
147
|
end
|
|
141
148
|
|
|
142
149
|
it 'sets phrase fields' do
|
|
@@ -145,7 +152,7 @@ shared_examples_for 'fulltext query' do
|
|
|
145
152
|
phrase_fields :title => 2.0
|
|
146
153
|
end
|
|
147
154
|
end
|
|
148
|
-
connection.
|
|
155
|
+
expect(connection).to have_last_search_with(:pf => 'title_text^2.0')
|
|
149
156
|
end
|
|
150
157
|
|
|
151
158
|
it 'sets phrase fields with boost' do
|
|
@@ -154,7 +161,7 @@ shared_examples_for 'fulltext query' do
|
|
|
154
161
|
phrase_fields :title => 1.5
|
|
155
162
|
end
|
|
156
163
|
end
|
|
157
|
-
connection.
|
|
164
|
+
expect(connection).to have_last_search_with(:pf => 'title_text^1.5')
|
|
158
165
|
end
|
|
159
166
|
|
|
160
167
|
it 'sets phrase slop from DSL' do
|
|
@@ -163,7 +170,7 @@ shared_examples_for 'fulltext query' do
|
|
|
163
170
|
phrase_slop 2
|
|
164
171
|
end
|
|
165
172
|
end
|
|
166
|
-
connection.
|
|
173
|
+
expect(connection).to have_last_search_with(:ps => 2)
|
|
167
174
|
end
|
|
168
175
|
|
|
169
176
|
it 'sets boost for certain fields without restricting fields' do
|
|
@@ -172,7 +179,9 @@ shared_examples_for 'fulltext query' do
|
|
|
172
179
|
boost_fields :title => 1.5
|
|
173
180
|
end
|
|
174
181
|
end
|
|
175
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
182
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
|
183
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text^1.5))
|
|
184
|
+
)
|
|
176
185
|
end
|
|
177
186
|
|
|
178
187
|
it 'ignores boost fields that do not apply' do
|
|
@@ -181,21 +190,24 @@ shared_examples_for 'fulltext query' do
|
|
|
181
190
|
boost_fields :bogus => 1.2, :title => 1.5
|
|
182
191
|
end
|
|
183
192
|
end
|
|
184
|
-
connection.searches.last[:qf].split(' ').sort.
|
|
193
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
|
194
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text^1.5))
|
|
195
|
+
)
|
|
185
196
|
end
|
|
186
197
|
|
|
187
198
|
it 'sets default boost with default fields' do
|
|
188
199
|
search Photo do
|
|
189
200
|
keywords 'great pizza'
|
|
190
201
|
end
|
|
191
|
-
|
|
202
|
+
# Hashes in 1.8 aren't ordered
|
|
203
|
+
expect(connection.searches.last[:qf].split(" ").sort.join(" ")).to eq 'caption_text^1.5 description_text'
|
|
192
204
|
end
|
|
193
205
|
|
|
194
206
|
it 'sets default boost with fields specified in options' do
|
|
195
207
|
search Photo do
|
|
196
208
|
keywords 'great pizza', :fields => [:caption]
|
|
197
209
|
end
|
|
198
|
-
connection.
|
|
210
|
+
expect(connection).to have_last_search_with(:qf => 'caption_text^1.5')
|
|
199
211
|
end
|
|
200
212
|
|
|
201
213
|
it 'sets default boost with fields specified in DSL' do
|
|
@@ -204,7 +216,7 @@ shared_examples_for 'fulltext query' do
|
|
|
204
216
|
fields :caption
|
|
205
217
|
end
|
|
206
218
|
end
|
|
207
|
-
connection.
|
|
219
|
+
expect(connection).to have_last_search_with(:qf => 'caption_text^1.5')
|
|
208
220
|
end
|
|
209
221
|
|
|
210
222
|
it 'overrides default boost when specified in DSL' do
|
|
@@ -213,7 +225,7 @@ shared_examples_for 'fulltext query' do
|
|
|
213
225
|
fields :caption => 2.0
|
|
214
226
|
end
|
|
215
227
|
end
|
|
216
|
-
connection.
|
|
228
|
+
expect(connection).to have_last_search_with(:qf => 'caption_text^2.0')
|
|
217
229
|
end
|
|
218
230
|
|
|
219
231
|
it 'creates boost query' do
|
|
@@ -224,7 +236,7 @@ shared_examples_for 'fulltext query' do
|
|
|
224
236
|
end
|
|
225
237
|
end
|
|
226
238
|
end
|
|
227
|
-
connection.
|
|
239
|
+
expect(connection).to have_last_search_with(:bq => ['average_rating_ft:{2\.0 TO *}^2.0'])
|
|
228
240
|
end
|
|
229
241
|
|
|
230
242
|
it 'creates multiple boost queries' do
|
|
@@ -238,7 +250,7 @@ shared_examples_for 'fulltext query' do
|
|
|
238
250
|
end
|
|
239
251
|
end
|
|
240
252
|
end
|
|
241
|
-
connection.
|
|
253
|
+
expect(connection).to have_last_search_with(
|
|
242
254
|
:bq => [
|
|
243
255
|
'average_rating_ft:{2\.0 TO *}^2.0',
|
|
244
256
|
'featured_bs:true^1.5'
|
|
@@ -250,64 +262,206 @@ shared_examples_for 'fulltext query' do
|
|
|
250
262
|
search do
|
|
251
263
|
keywords 'great pizza', :minimum_match => 2
|
|
252
264
|
end
|
|
253
|
-
connection.
|
|
265
|
+
expect(connection).to have_last_search_with(:mm => 2)
|
|
254
266
|
end
|
|
255
267
|
|
|
256
268
|
it 'sends minimum match parameter from DSL' do
|
|
257
269
|
search do
|
|
258
270
|
keywords('great pizza') { minimum_match(2) }
|
|
259
271
|
end
|
|
260
|
-
connection.
|
|
272
|
+
expect(connection).to have_last_search_with(:mm => 2)
|
|
261
273
|
end
|
|
262
274
|
|
|
263
275
|
it 'sends tiebreaker parameter from options' do
|
|
264
276
|
search do
|
|
265
277
|
keywords 'great pizza', :tie => 0.1
|
|
266
278
|
end
|
|
267
|
-
connection.
|
|
279
|
+
expect(connection).to have_last_search_with(:tie => 0.1)
|
|
268
280
|
end
|
|
269
281
|
|
|
270
282
|
it 'sends tiebreaker parameter from DSL' do
|
|
271
283
|
search do
|
|
272
284
|
keywords('great pizza') { tie(0.1) }
|
|
273
285
|
end
|
|
274
|
-
connection.
|
|
286
|
+
expect(connection).to have_last_search_with(:tie => 0.1)
|
|
275
287
|
end
|
|
276
288
|
|
|
277
289
|
it 'sends query phrase slop from options' do
|
|
278
290
|
search do
|
|
279
291
|
keywords 'great pizza', :query_phrase_slop => 2
|
|
280
292
|
end
|
|
281
|
-
connection.
|
|
293
|
+
expect(connection).to have_last_search_with(:qs => 2)
|
|
282
294
|
end
|
|
283
295
|
|
|
284
296
|
it 'sends query phrase slop from DSL' do
|
|
285
297
|
search do
|
|
286
298
|
keywords('great pizza') { query_phrase_slop(2) }
|
|
287
299
|
end
|
|
288
|
-
connection.
|
|
300
|
+
expect(connection).to have_last_search_with(:qs => 2)
|
|
289
301
|
end
|
|
290
302
|
|
|
291
303
|
it 'allows specification of a text field that only exists in one type' do
|
|
292
304
|
search Post, Namespaced::Comment do
|
|
293
305
|
keywords 'keywords', :fields => :author_name
|
|
294
306
|
end
|
|
295
|
-
connection.searches.last[:qf].
|
|
307
|
+
expect(connection.searches.last[:qf]).to eq('author_name_text')
|
|
296
308
|
end
|
|
297
309
|
|
|
298
310
|
it 'raises Sunspot::UnrecognizedFieldError for nonexistant fields in keywords' do
|
|
299
|
-
|
|
311
|
+
expect do
|
|
300
312
|
search do
|
|
301
313
|
keywords :text, :fields => :bogus
|
|
302
314
|
end
|
|
303
|
-
end.
|
|
315
|
+
end.to raise_error(Sunspot::UnrecognizedFieldError)
|
|
304
316
|
end
|
|
305
317
|
|
|
306
318
|
it 'raises Sunspot::UnrecognizedFieldError if a text field that does not exist for any type is specified' do
|
|
307
|
-
|
|
319
|
+
expect do
|
|
308
320
|
search Post, Namespaced::Comment do
|
|
309
321
|
keywords 'fulltext', :fields => :bogus
|
|
310
322
|
end
|
|
311
|
-
end.
|
|
323
|
+
end.to raise_error(Sunspot::UnrecognizedFieldError)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
describe 'connective examples' do
|
|
327
|
+
it 'creates a disjunction between two subqueries' do
|
|
328
|
+
search Post do
|
|
329
|
+
any do
|
|
330
|
+
fulltext 'keywords1', :fields => :title
|
|
331
|
+
fulltext 'keyword2', :fields => :body
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='title_text'}keywords1\" OR _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it 'creates a conjunction inside of a disjunction' do
|
|
339
|
+
search do
|
|
340
|
+
any do
|
|
341
|
+
fulltext 'keywords1', :fields => :body
|
|
342
|
+
|
|
343
|
+
all do
|
|
344
|
+
fulltext 'keyword2', :fields => :body
|
|
345
|
+
fulltext 'keyword3', :fields => :body
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='body_textsv'}keywords1\" OR (_query_:\"{!edismax qf='body_textsv'}keyword2\" AND _query_:\"{!edismax qf='body_textsv'}keyword3\"))"
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
it 'does nothing special if #all/#any called from the top level or called multiple times' do
|
|
354
|
+
search Post do
|
|
355
|
+
all do
|
|
356
|
+
fulltext 'keywords1', :fields => :title
|
|
357
|
+
fulltext 'keyword2', :fields => :body
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='title_text'}keywords1\" AND _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it 'does nothing special if #all/#any are mixed and called multiple times' do
|
|
365
|
+
search Post do
|
|
366
|
+
all do
|
|
367
|
+
any do
|
|
368
|
+
all do
|
|
369
|
+
fulltext 'keywords1', :fields => :title
|
|
370
|
+
fulltext 'keyword2', :fields => :body
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='title_text'}keywords1\" AND _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
|
377
|
+
|
|
378
|
+
search Post do
|
|
379
|
+
any do
|
|
380
|
+
all do
|
|
381
|
+
any do
|
|
382
|
+
fulltext 'keywords1', :fields => :title
|
|
383
|
+
fulltext 'keyword2', :fields => :body
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='title_text'}keywords1\" OR _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
it "does not add empty parentheses" do
|
|
393
|
+
search Post do
|
|
394
|
+
any do
|
|
395
|
+
all do
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
any do
|
|
399
|
+
fulltext 'keywords1', :fields => :title
|
|
400
|
+
all do
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
expect(connection.searches.last[:q]).to eq "_query_:\"{!edismax qf='title_text'}keywords1\""
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
describe "joins" do
|
|
411
|
+
it "should search by join" do
|
|
412
|
+
srch = search PhotoContainer do
|
|
413
|
+
any do
|
|
414
|
+
fulltext 'keyword1', :fields => :caption
|
|
415
|
+
fulltext 'keyword2', :fields => :description
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
obj_id = find_ob_id(srch)
|
|
420
|
+
q_name = "qPhoto#{obj_id}"
|
|
421
|
+
|
|
422
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name}}\" OR _query_:\"{!edismax qf='description_text^1.2'}keyword2\")"
|
|
423
|
+
expect(connection.searches.last[q_name]).to eq "_query_:\"{!field f=type}Photo\"+_query_:\"{!edismax qf='caption_text'}keyword1\""
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
it "should be able to resolve name conflicts with the :prefix option" do
|
|
427
|
+
srch = search PhotoContainer do
|
|
428
|
+
any do
|
|
429
|
+
fulltext 'keyword1', :fields => :description
|
|
430
|
+
fulltext 'keyword2', :fields => :photo_description
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
obj_id = find_ob_id(srch)
|
|
435
|
+
q_name = "qPhoto#{obj_id}"
|
|
436
|
+
|
|
437
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='description_text^1.2'}keyword1\" OR _query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name}}\")"
|
|
438
|
+
expect(connection.searches.last[q_name]).to eq "_query_:\"{!field f=type}Photo\"+_query_:\"{!edismax qf='description_text'}keyword2\""
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
it "should recognize fields when adding from DSL, e.g. when calling boost_fields" do
|
|
442
|
+
srch = search PhotoContainer do
|
|
443
|
+
any do
|
|
444
|
+
fulltext 'keyword1', :fields => [:photo_description, :description] do
|
|
445
|
+
boost_fields(:photo_description => 1.3, :description => 1.5)
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
obj_id = find_ob_id(srch)
|
|
451
|
+
q_name = "qPhoto#{obj_id}"
|
|
452
|
+
|
|
453
|
+
expect(connection.searches.last[:q]).to eq "(_query_:\"{!edismax qf='description_text^1.5'}keyword1\" OR _query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name}}\")"
|
|
454
|
+
expect(connection.searches.last[q_name]).to eq "_query_:\"{!field f=type}Photo\"+_query_:\"{!edismax qf='description_text^1.3'}keyword1\""
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
private
|
|
458
|
+
|
|
459
|
+
def find_ob_id(search)
|
|
460
|
+
search.query.
|
|
461
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Conjunction) }.
|
|
462
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Disjunction) }.
|
|
463
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Join) }.
|
|
464
|
+
object_id
|
|
465
|
+
end
|
|
312
466
|
end
|
|
313
467
|
end
|