sunspot 0.10.5 → 0.10.6
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.
- data/History.txt +13 -0
- data/README.rdoc +3 -3
- data/TODO +4 -5
- data/VERSION.yml +1 -1
- data/bin/sunspot-solr +18 -6
- data/lib/sunspot/dsl/field_query.rb +69 -18
- data/lib/sunspot/dsl/fields.rb +6 -5
- data/lib/sunspot/dsl/fulltext.rb +57 -1
- data/lib/sunspot/dsl/query.rb +30 -3
- data/lib/sunspot/dsl/query_facet.rb +8 -3
- data/lib/sunspot/dsl/search.rb +1 -1
- data/lib/sunspot/dsl.rb +1 -1
- data/lib/sunspot/field_factory.rb +6 -3
- data/lib/sunspot/query/abstract_field_facet.rb +43 -0
- data/lib/sunspot/query/date_field_facet.rb +14 -0
- data/lib/sunspot/query/dismax.rb +26 -7
- data/lib/sunspot/query/field_facet.rb +2 -122
- data/lib/sunspot/query/highlighting.rb +17 -5
- data/lib/sunspot/query/query.rb +12 -23
- data/lib/sunspot/query/query_facet.rb +4 -66
- data/lib/sunspot/query.rb +5 -1
- data/lib/sunspot/search/date_facet.rb +35 -0
- data/lib/sunspot/search/facet_row.rb +27 -0
- data/lib/sunspot/search/field_facet.rb +44 -0
- data/lib/sunspot/search/hit.rb +10 -6
- data/lib/sunspot/search/query_facet.rb +62 -0
- data/lib/sunspot/search.rb +22 -44
- data/lib/sunspot/setup.rb +22 -7
- data/lib/sunspot/type.rb +4 -0
- data/lib/sunspot/util.rb +8 -0
- data/lib/sunspot.rb +7 -6
- data/solr/solr/conf/solrconfig.xml +1 -2
- data/solr/solr/lib/locallucene.jar +0 -0
- data/solr/solr/lib/localsolr.jar +0 -0
- data/spec/api/indexer/attributes_spec.rb +5 -0
- data/spec/api/query/faceting_spec.rb +24 -0
- data/spec/api/query/fulltext_spec.rb +80 -1
- data/spec/api/query/highlighting_spec.rb +84 -6
- data/spec/api/search/faceting_spec.rb +45 -9
- data/spec/api/search/highlighting_spec.rb +2 -2
- data/spec/api/search/hits_spec.rb +5 -0
- data/spec/integration/faceting_spec.rb +19 -0
- data/spec/integration/keyword_search_spec.rb +101 -4
- data/spec/mocks/photo.rb +3 -0
- data/tasks/gemspec.rake +8 -2
- data/tasks/rcov.rake +2 -2
- metadata +9 -11
- data/lib/sunspot/facet.rb +0 -24
- data/lib/sunspot/facet_data.rb +0 -169
- data/lib/sunspot/facet_row.rb +0 -12
- data/lib/sunspot/instantiated_facet.rb +0 -39
- data/lib/sunspot/instantiated_facet_row.rb +0 -27
- data/lib/sunspot/query/fulltext_base_query.rb +0 -47
- data/lib/sunspot/query/query_facet_row.rb +0 -19
- data/lib/sunspot/query/query_field_facet.rb +0 -20
data/lib/sunspot/setup.rb
CHANGED
@@ -10,6 +10,7 @@ module Sunspot
|
|
10
10
|
@field_factories, @text_field_factories, @dynamic_field_factories,
|
11
11
|
@field_factories_cache, @text_field_factories_cache,
|
12
12
|
@dynamic_field_factories_cache = *Array.new(6) { Hash.new }
|
13
|
+
@stored_field_factories_cache = Hash.new { |h, k| h[k] = [] }
|
13
14
|
@dsl = DSL::Fields.new(self)
|
14
15
|
add_field_factory(:class, Type::ClassType)
|
15
16
|
end
|
@@ -19,16 +20,16 @@ module Sunspot
|
|
19
20
|
end
|
20
21
|
|
21
22
|
#
|
22
|
-
# Add
|
23
|
-
#
|
24
|
-
# ==== Parameters
|
25
|
-
#
|
26
|
-
# field_factories<Array>:: Array of Sunspot::Field objects
|
23
|
+
# Add field factory for scope/ordering
|
27
24
|
#
|
28
25
|
def add_field_factory(name, type, options = {}, &block)
|
26
|
+
stored = options[:stored]
|
29
27
|
field_factory = FieldFactory::Static.new(name, type, options, &block)
|
30
28
|
@field_factories[field_factory.signature] = field_factory
|
31
29
|
@field_factories_cache[field_factory.name] = field_factory
|
30
|
+
if stored
|
31
|
+
@stored_field_factories_cache[field_factory.name] << field_factory
|
32
|
+
end
|
32
33
|
end
|
33
34
|
|
34
35
|
#
|
@@ -39,9 +40,13 @@ module Sunspot
|
|
39
40
|
# field_factories<Array>:: Array of Sunspot::Field objects
|
40
41
|
#
|
41
42
|
def add_text_field_factory(name, options = {}, &block)
|
43
|
+
stored = options[:stored]
|
42
44
|
field_factory = FieldFactory::Static.new(name, Type::TextType, options, &block)
|
43
45
|
@text_field_factories[name] = field_factory
|
44
46
|
@text_field_factories_cache[field_factory.name] = field_factory
|
47
|
+
if stored
|
48
|
+
@stored_field_factories_cache[field_factory.name] << field_factory
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
52
|
#
|
@@ -62,8 +67,8 @@ module Sunspot
|
|
62
67
|
# of documents during index, but does not actually generate fields (since
|
63
68
|
# the field names used in search are static).
|
64
69
|
#
|
65
|
-
def set_coordinates_field(name)
|
66
|
-
@coordinates_field_factory = FieldFactory::Coordinates.new(name)
|
70
|
+
def set_coordinates_field(name = nil, &block)
|
71
|
+
@coordinates_field_factory = FieldFactory::Coordinates.new(name, &block)
|
67
72
|
end
|
68
73
|
|
69
74
|
#
|
@@ -123,6 +128,16 @@ module Sunspot
|
|
123
128
|
[text_field]
|
124
129
|
end
|
125
130
|
|
131
|
+
#
|
132
|
+
# Return one or more stored fields (can be either attribute or text fields)
|
133
|
+
# for the given name.
|
134
|
+
#
|
135
|
+
def stored_fields(field_name)
|
136
|
+
@stored_field_factories_cache[field_name.to_sym].map do |field_factory|
|
137
|
+
field_factory.build
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
126
141
|
#
|
127
142
|
# Return the DynamicFieldFactory with the given base name
|
128
143
|
#
|
data/lib/sunspot/type.rb
CHANGED
data/lib/sunspot/util.rb
CHANGED
@@ -87,6 +87,14 @@ module Sunspot
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
def extract_options_from(args)
|
91
|
+
if args.last.is_a?(Hash)
|
92
|
+
args.pop
|
93
|
+
else
|
94
|
+
{}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
90
98
|
#
|
91
99
|
# Perform a deep merge of hashes, returning the result as a new hash.
|
92
100
|
# See #deep_merge_into for rules used to merge the hashes
|
data/lib/sunspot.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'time'
|
3
|
+
require 'date'
|
4
|
+
require 'enumerator'
|
1
5
|
begin
|
2
|
-
require 'time'
|
3
|
-
require 'date'
|
4
6
|
require 'rsolr'
|
5
7
|
rescue LoadError
|
6
8
|
require 'rubygems'
|
@@ -10,8 +12,7 @@ end
|
|
10
12
|
require File.join(File.dirname(__FILE__), 'light_config')
|
11
13
|
|
12
14
|
%w(util adapters configuration setup composite_setup text_field_setup field
|
13
|
-
field_factory data_extractor indexer query search
|
14
|
-
instantiated_facet instantiated_facet_row facet_data session type
|
15
|
+
field_factory data_extractor indexer query search session type
|
15
16
|
dsl).each do |filename|
|
16
17
|
require File.join(File.dirname(__FILE__), 'sunspot', filename)
|
17
18
|
end
|
@@ -210,7 +211,7 @@ module Sunspot
|
|
210
211
|
# ==== Parameters
|
211
212
|
#
|
212
213
|
# types<Class>...::
|
213
|
-
#
|
214
|
+
# One or more types to search for. If no types are passed, all
|
214
215
|
# configured types will be searched for.
|
215
216
|
#
|
216
217
|
# ==== Returns
|
@@ -229,7 +230,7 @@ module Sunspot
|
|
229
230
|
# ==== Parameters
|
230
231
|
#
|
231
232
|
# types<Class>...::
|
232
|
-
#
|
233
|
+
# One or more types to search for. If no types are passed, all
|
233
234
|
# configured types will be searched.
|
234
235
|
#
|
235
236
|
# ==== Returns
|
@@ -682,9 +682,7 @@
|
|
682
682
|
</queryResponseWriter>
|
683
683
|
|
684
684
|
|
685
|
-
<!-- example of registering a query parser
|
686
685
|
<queryParser name="lucene" class="org.apache.solr.search.LuceneQParserPlugin"/>
|
687
|
-
-->
|
688
686
|
|
689
687
|
<!-- example of registering a custom function parser
|
690
688
|
<valueSourceParser name="myfunc" class="com.mycompany.MyValueSourceParser" />
|
@@ -715,6 +713,7 @@
|
|
715
713
|
<str name='lngField'>long</str>
|
716
714
|
</searchComponent>
|
717
715
|
<requestHandler class='org.apache.solr.handler.component.SearchHandler' name='geo'>
|
716
|
+
<str name="defType">lucene</str>
|
718
717
|
<arr name='components'>
|
719
718
|
<str>localsolr</str>
|
720
719
|
<str>facet</str>
|
Binary file
|
data/solr/solr/lib/localsolr.jar
CHANGED
Binary file
|
@@ -66,6 +66,11 @@ describe 'indexing attribute fields', :type => :indexer do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
it 'should index latitude and longitude from a block' do
|
70
|
+
session.index(Photo.new(:lat => 30, :lng => -60))
|
71
|
+
connection.should have_add_with(:lat => 30, :long => -60)
|
72
|
+
end
|
73
|
+
|
69
74
|
it 'should correctly index an attribute field with block access' do
|
70
75
|
session.index(post(:title => 'The Blog Post'))
|
71
76
|
connection.should have_add_with(:sort_title_s => 'blog post')
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
1
3
|
describe 'faceting' do
|
2
4
|
describe 'on fields' do
|
3
5
|
it 'does not turn faceting on if no facet requested' do
|
@@ -75,6 +77,28 @@ describe 'faceting' do
|
|
75
77
|
end
|
76
78
|
connection.should have_last_search_with(:"f.category_ids_im.facet.mincount" => 1)
|
77
79
|
end
|
80
|
+
|
81
|
+
it 'sends a query facet for :any extra' do
|
82
|
+
session.search Post do
|
83
|
+
facet :category_ids, :extra => :any
|
84
|
+
end
|
85
|
+
connection.should have_last_search_with(:"facet.query" => "category_ids_im:[* TO *]")
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'sends a query facet for :none extra' do
|
89
|
+
session.search Post do
|
90
|
+
facet :category_ids, :extra => :none
|
91
|
+
end
|
92
|
+
connection.should have_last_search_with(:"facet.query" => "-category_ids_im:[* TO *]")
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'raises an ArgumentError if bogus extra is passed' do
|
96
|
+
lambda do
|
97
|
+
session.search Post do
|
98
|
+
facet :category_ids, :extra => :bogus
|
99
|
+
end
|
100
|
+
end.should raise_error(ArgumentError)
|
101
|
+
end
|
78
102
|
end
|
79
103
|
|
80
104
|
describe 'on time ranges' do
|
@@ -70,6 +70,15 @@ describe 'fulltext query', :type => :query do
|
|
70
70
|
connection.searches.last[:qf].split(' ').sort.should == %w(body_texts title_text)
|
71
71
|
end
|
72
72
|
|
73
|
+
it 'excludes text fields when instructed' do
|
74
|
+
session.search Post do
|
75
|
+
keywords 'keyword search' do
|
76
|
+
exclude_fields :backwards_title
|
77
|
+
end
|
78
|
+
end
|
79
|
+
connection.searches.last[:qf].split(' ').sort.should == %w(body_texts title_text)
|
80
|
+
end
|
81
|
+
|
73
82
|
it 'assigns boost to fields when specified' do
|
74
83
|
session.search Post do
|
75
84
|
keywords 'keyword search' do
|
@@ -124,6 +133,15 @@ describe 'fulltext query', :type => :query do
|
|
124
133
|
connection.should have_last_search_with(:pf => 'title_text^1.5')
|
125
134
|
end
|
126
135
|
|
136
|
+
it 'sets phrase slop from DSL' do
|
137
|
+
session.search Post do
|
138
|
+
keywords 'great pizza' do
|
139
|
+
phrase_slop 2
|
140
|
+
end
|
141
|
+
end
|
142
|
+
connection.should have_last_search_with(:ps => 2)
|
143
|
+
end
|
144
|
+
|
127
145
|
it 'sets boost for certain fields without restricting fields' do
|
128
146
|
session.search Post do
|
129
147
|
keywords 'great pizza' do
|
@@ -173,7 +191,68 @@ describe 'fulltext query', :type => :query do
|
|
173
191
|
end
|
174
192
|
end
|
175
193
|
end
|
176
|
-
connection.should have_last_search_with(:bq => 'average_rating_f:[2\.0 TO *]^2.0')
|
194
|
+
connection.should have_last_search_with(:bq => ['average_rating_f:[2\.0 TO *]^2.0'])
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'creates multiple boost queries' do
|
198
|
+
session.search Post do
|
199
|
+
keywords 'great pizza' do
|
200
|
+
boost(2.0) do
|
201
|
+
with(:average_rating).greater_than(2.0)
|
202
|
+
end
|
203
|
+
boost(1.5) do
|
204
|
+
with(:featured, true)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
connection.should have_last_search_with(
|
209
|
+
:bq => [
|
210
|
+
'average_rating_f:[2\.0 TO *]^2.0',
|
211
|
+
'featured_b:true^1.5'
|
212
|
+
]
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'sends minimum match parameter from options' do
|
217
|
+
session.search Post do
|
218
|
+
keywords 'great pizza', :minimum_match => 2
|
219
|
+
end
|
220
|
+
connection.should have_last_search_with(:mm => 2)
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'sends minimum match parameter from DSL' do
|
224
|
+
session.search Post do
|
225
|
+
keywords('great pizza') { minimum_match(2) }
|
226
|
+
end
|
227
|
+
connection.should have_last_search_with(:mm => 2)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'sends tiebreaker parameter from options' do
|
231
|
+
session.search Post do
|
232
|
+
keywords 'great pizza', :tie => 0.1
|
233
|
+
end
|
234
|
+
connection.should have_last_search_with(:tie => 0.1)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'sends tiebreaker parameter from DSL' do
|
238
|
+
session.search Post do
|
239
|
+
keywords('great pizza') { tie(0.1) }
|
240
|
+
end
|
241
|
+
connection.should have_last_search_with(:tie => 0.1)
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'sends query phrase slop from options' do
|
245
|
+
session.search Post do
|
246
|
+
keywords 'great pizza', :query_phrase_slop => 2
|
247
|
+
end
|
248
|
+
connection.should have_last_search_with(:qs => 2)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'sends query phrase slop from DSL' do
|
252
|
+
session.search Post do
|
253
|
+
keywords('great pizza') { query_phrase_slop(2) }
|
254
|
+
end
|
255
|
+
connection.should have_last_search_with(:qs => 2)
|
177
256
|
end
|
178
257
|
|
179
258
|
it 'allows specification of a text field that only exists in one type' do
|
@@ -77,15 +77,24 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
77
77
|
)
|
78
78
|
end
|
79
79
|
|
80
|
-
it 'should set
|
80
|
+
it 'should set highlight fields from DSL' do
|
81
81
|
session.search(Post) do
|
82
82
|
keywords 'test' do
|
83
|
-
highlight :title
|
83
|
+
highlight :title
|
84
84
|
end
|
85
85
|
end
|
86
86
|
connection.should have_last_search_with(
|
87
|
-
:"hl.fl"
|
88
|
-
|
87
|
+
:"hl.fl" => %w(title_text)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not set formatting params specific to fields if fields specified' do
|
92
|
+
session.search(Post) do
|
93
|
+
keywords 'test', :highlight => :body
|
94
|
+
end
|
95
|
+
connection.should have_last_search_with(
|
96
|
+
:"hl.simple.pre" => '@@@hl@@@',
|
97
|
+
:"hl.simple.post" => '@@@endhl@@@'
|
89
98
|
)
|
90
99
|
end
|
91
100
|
|
@@ -100,6 +109,18 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
100
109
|
)
|
101
110
|
end
|
102
111
|
|
112
|
+
it 'should set max snippets specific to highlight fields' do
|
113
|
+
session.search(Post) do
|
114
|
+
keywords 'test' do
|
115
|
+
highlight :title, :max_snippets => 3
|
116
|
+
end
|
117
|
+
end
|
118
|
+
connection.should have_last_search_with(
|
119
|
+
:"hl.fl" => %w(title_text),
|
120
|
+
:"f.title_text.hl.snippets" => 3
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
103
124
|
it 'should set the maximum size' do
|
104
125
|
session.search(Post) do
|
105
126
|
keywords 'text' do
|
@@ -111,7 +132,18 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
111
132
|
)
|
112
133
|
end
|
113
134
|
|
114
|
-
it '
|
135
|
+
it 'should set the maximum size for specific fields' do
|
136
|
+
session.search(Post) do
|
137
|
+
keywords 'text' do
|
138
|
+
highlight :title, :fragment_size => 200
|
139
|
+
end
|
140
|
+
end
|
141
|
+
connection.should have_last_search_with(
|
142
|
+
:"f.title_text.hl.fragsize" => 200
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'enables merging of contiguous fragments' do
|
115
147
|
session.search(Post) do
|
116
148
|
keywords 'test' do
|
117
149
|
highlight :merge_contiguous_fragments => true
|
@@ -122,7 +154,18 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
122
154
|
)
|
123
155
|
end
|
124
156
|
|
125
|
-
it 'enables
|
157
|
+
it 'enables merging of contiguous fragments for specific fields' do
|
158
|
+
session.search(Post) do
|
159
|
+
keywords 'test' do
|
160
|
+
highlight :title, :merge_contiguous_fragments => true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
connection.should have_last_search_with(
|
164
|
+
:"f.title_text.hl.mergeContiguous" => 'true'
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'enables use of phrase highlighter' do
|
126
169
|
session.search(Post) do
|
127
170
|
keywords 'test' do
|
128
171
|
highlight :phrase_highlighter => true
|
@@ -133,6 +176,17 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
133
176
|
)
|
134
177
|
end
|
135
178
|
|
179
|
+
it 'enables use of phrase highlighter for specific fields' do
|
180
|
+
session.search(Post) do
|
181
|
+
keywords 'test' do
|
182
|
+
highlight :title, :phrase_highlighter => true
|
183
|
+
end
|
184
|
+
end
|
185
|
+
connection.should have_last_search_with(
|
186
|
+
:"f.title_text.hl.usePhraseHighlighter" => 'true'
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
136
190
|
it 'requires field match if requested' do
|
137
191
|
session.search(Post) do
|
138
192
|
keywords 'test' do
|
@@ -144,4 +198,28 @@ describe 'highlighted fulltext queries', :type => :query do
|
|
144
198
|
)
|
145
199
|
end
|
146
200
|
|
201
|
+
it 'requires field match for specified field if requested' do
|
202
|
+
session.search(Post) do
|
203
|
+
keywords 'test' do
|
204
|
+
highlight :title, :phrase_highlighter => true, :require_field_match => true
|
205
|
+
end
|
206
|
+
end
|
207
|
+
connection.should have_last_search_with(
|
208
|
+
:"f.title_text.hl.requireFieldMatch" => 'true'
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'sets field specific params for different fields if different params given' do
|
213
|
+
session.search(Post) do
|
214
|
+
keywords 'test' do
|
215
|
+
highlight :title, :max_snippets => 2
|
216
|
+
highlight :body, :max_snippets => 1
|
217
|
+
end
|
218
|
+
end
|
219
|
+
connection.should have_last_search_with(
|
220
|
+
:"hl.fl" => %w(title_text body_texts),
|
221
|
+
:"f.title_text.hl.snippets" => 2,
|
222
|
+
:"f.body_texts.hl.snippets" => 1
|
223
|
+
)
|
224
|
+
end
|
147
225
|
end
|
@@ -81,6 +81,26 @@ describe 'faceting', :type => :search do
|
|
81
81
|
facet_values(result, :class).should == [Post, Namespaced::Comment]
|
82
82
|
end
|
83
83
|
|
84
|
+
it 'should return special :any facet' do
|
85
|
+
stub_query_facet(
|
86
|
+
'category_ids_im:[* TO *]' => 3
|
87
|
+
)
|
88
|
+
search = session.search(Post) { facet(:category_ids, :extra => :any) }
|
89
|
+
row = search.facet(:category_ids).rows.first
|
90
|
+
row.value.should == :any
|
91
|
+
row.count.should == 3
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should return special :none facet' do
|
95
|
+
stub_query_facet(
|
96
|
+
'-category_ids_im:[* TO *]' => 3
|
97
|
+
)
|
98
|
+
search = session.search(Post) { facet(:category_ids, :extra => :none) }
|
99
|
+
row = search.facet(:category_ids).rows.first
|
100
|
+
row.value.should == :none
|
101
|
+
row.count.should == 3
|
102
|
+
end
|
103
|
+
|
84
104
|
it 'should return date range facet' do
|
85
105
|
stub_date_facet(:published_at_d, 60*60*24, '2009-07-08T04:00:00Z' => 2, '2009-07-07T04:00:00Z' => 1)
|
86
106
|
start_time = Time.utc(2009, 7, 7, 4)
|
@@ -91,6 +111,16 @@ describe 'faceting', :type => :search do
|
|
91
111
|
facet.rows.last.value.should == ((start_time+24*60*60)..end_time)
|
92
112
|
end
|
93
113
|
|
114
|
+
it 'should return date range facet sorted by count' do
|
115
|
+
stub_date_facet(:published_at_d, 60*60*24, '2009-07-08T04:00:00Z' => 2, '2009-07-07T04:00:00Z' => 1)
|
116
|
+
start_time = Time.utc(2009, 7, 7, 4)
|
117
|
+
end_time = start_time + 2*24*60*60
|
118
|
+
result = session.search(Post) { facet(:published_at, :time_range => start_time..end_time, :sort => :count) }
|
119
|
+
facet = result.facet(:published_at)
|
120
|
+
facet.rows.first.value.should == ((start_time+24*60*60)..end_time)
|
121
|
+
facet.rows.last.value.should == (start_time..(start_time+24*60*60))
|
122
|
+
end
|
123
|
+
|
94
124
|
it 'returns query facet' do
|
95
125
|
stub_query_facet(
|
96
126
|
'average_rating_f:[3\.0 TO 5\.0]' => 3,
|
@@ -118,22 +148,28 @@ describe 'faceting', :type => :search do
|
|
118
148
|
session.search(Post) do
|
119
149
|
facet :average_rating, options do
|
120
150
|
row(1) { with(:average_rating, 1.0..2.0) }
|
121
|
-
row(2) { with(:average_rating, 2.0..3.0) }
|
122
151
|
row(3) { with(:average_rating, 3.0..4.0) }
|
152
|
+
row(2) { with(:average_rating, 2.0..3.0) }
|
153
|
+
row(4) { with(:average_rating, 4.0..5.0) }
|
123
154
|
end
|
124
155
|
end.facet(:average_rating).rows.map { |row| row.value }
|
125
156
|
end
|
126
157
|
|
127
158
|
before :each do
|
128
159
|
stub_query_facet(
|
129
|
-
'average_rating_f:[1\.0 TO 2\.0]' =>
|
130
|
-
'average_rating_f:[2\.0 TO 3\.0]' =>
|
131
|
-
'average_rating_f:[3\.0 TO 4\.0]' =>
|
160
|
+
'average_rating_f:[1\.0 TO 2\.0]' => 2,
|
161
|
+
'average_rating_f:[2\.0 TO 3\.0]' => 3,
|
162
|
+
'average_rating_f:[3\.0 TO 4\.0]' => 1,
|
163
|
+
'average_rating_f:[4\.0 TO 5\.0]' => 0
|
132
164
|
)
|
133
165
|
end
|
134
166
|
|
135
|
-
it 'sorts
|
136
|
-
facet_values_from_options.should == [1, 2]
|
167
|
+
it 'sorts in order of specification if no limit is given' do
|
168
|
+
facet_values_from_options.should == [1, 3, 2]
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'sorts lexically if lexical option is specified' do
|
172
|
+
facet_values_from_options(:sort => :index).should == [1, 2, 3]
|
137
173
|
end
|
138
174
|
|
139
175
|
it 'sorts by count by default if limit is given' do
|
@@ -141,7 +177,7 @@ describe 'faceting', :type => :search do
|
|
141
177
|
end
|
142
178
|
|
143
179
|
it 'sorts by count if count option is specified' do
|
144
|
-
facet_values_from_options(:sort => :count).should == [2, 1]
|
180
|
+
facet_values_from_options(:sort => :count).should == [2, 1, 3]
|
145
181
|
end
|
146
182
|
|
147
183
|
it 'sorts lexically if lexical option is specified even if limit is given' do
|
@@ -153,11 +189,11 @@ describe 'faceting', :type => :search do
|
|
153
189
|
end
|
154
190
|
|
155
191
|
it 'allows zero count if specified' do
|
156
|
-
facet_values_from_options(:zeros => true).should == [1, 2,
|
192
|
+
facet_values_from_options(:zeros => true).should == [1, 3, 2, 4]
|
157
193
|
end
|
158
194
|
|
159
195
|
it 'sets minimum count' do
|
160
|
-
facet_values_from_options(:minimum_count => 2).should == [2]
|
196
|
+
facet_values_from_options(:minimum_count => 2).should == [1, 2]
|
161
197
|
end
|
162
198
|
end
|
163
199
|
|
@@ -21,8 +21,8 @@ describe 'search with highlighting results', :type => :search do
|
|
21
21
|
@search.hits.last.should have(2).highlights(:body)
|
22
22
|
end
|
23
23
|
|
24
|
-
it 'returns
|
25
|
-
@search.hits.first.highlights(:body).should
|
24
|
+
it 'returns an empty array if a given field does not have a highlight' do
|
25
|
+
@search.hits.first.highlights(:body).should == []
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should format hits with <em> by default' do
|
@@ -44,6 +44,11 @@ describe 'hits', :type => :search do
|
|
44
44
|
session.search(Post, Namespaced::Comment).hits.first.stored(:title).should == 'Title'
|
45
45
|
end
|
46
46
|
|
47
|
+
it 'should return stored text fields' do
|
48
|
+
stub_full_results('instance' => Post.new, 'body_texts' => 'Body')
|
49
|
+
session.search(Post, Namespaced::Comment).hits.first.stored(:body).should == 'Body'
|
50
|
+
end
|
51
|
+
|
47
52
|
it 'should typecast stored field values in hits' do
|
48
53
|
time = Time.utc(2008, 7, 8, 2, 45)
|
49
54
|
stub_full_results('instance' => Post.new, 'last_indexed_at_ds' => time.xmlschema)
|
@@ -46,6 +46,7 @@ describe 'search faceting' do
|
|
46
46
|
facet_values.each_with_index do |value, i|
|
47
47
|
i.times { Sunspot.index(Post.new(:title => value, :blog_id => 1)) }
|
48
48
|
end
|
49
|
+
Sunspot.index(Post.new(:blog_id => 1))
|
49
50
|
Sunspot.index(Post.new(:title => 'zero', :blog_id => 2))
|
50
51
|
Sunspot.commit
|
51
52
|
end
|
@@ -96,6 +97,24 @@ describe 'search faceting' do
|
|
96
97
|
end
|
97
98
|
search.facet(:title).rows.map { |row| row.value }.should == %w(four three two one)
|
98
99
|
end
|
100
|
+
|
101
|
+
it 'should return :all facet' do
|
102
|
+
search = Sunspot.search(Post) do
|
103
|
+
with :blog_id, 1
|
104
|
+
facet :title, :extra => :any
|
105
|
+
end
|
106
|
+
search.facet(:title).rows.first.value.should == :any
|
107
|
+
search.facet(:title).rows.first.count.should == 10
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should return :none facet' do
|
111
|
+
search = Sunspot.search(Post) do
|
112
|
+
with :blog_id, 1
|
113
|
+
facet :title, :extra => :none
|
114
|
+
end
|
115
|
+
search.facet(:title).rows.first.value.should == :none
|
116
|
+
search.facet(:title).rows.first.count.should == 1
|
117
|
+
end
|
99
118
|
end
|
100
119
|
|
101
120
|
context 'date facets' do
|