gojee-sunspot 2.0.3 → 2.0.4
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/.gitignore +12 -0
- data/Gemfile +5 -0
- data/History.txt +252 -0
- data/LICENSE +18 -0
- data/Rakefile +13 -0
- data/TODO +13 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot/adapters.rb +265 -0
- data/lib/sunspot/batcher.rb +62 -0
- data/lib/sunspot/class_set.rb +23 -0
- data/lib/sunspot/composite_setup.rb +202 -0
- data/lib/sunspot/configuration.rb +53 -0
- data/lib/sunspot/data_extractor.rb +50 -0
- data/lib/sunspot/dsl/adjustable.rb +47 -0
- data/lib/sunspot/dsl/field_group.rb +57 -0
- data/lib/sunspot/dsl/field_query.rb +327 -0
- data/lib/sunspot/dsl/fields.rb +103 -0
- data/lib/sunspot/dsl/fulltext.rb +243 -0
- data/lib/sunspot/dsl/function.rb +27 -0
- data/lib/sunspot/dsl/functional.rb +44 -0
- data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
- data/lib/sunspot/dsl/paginatable.rb +32 -0
- data/lib/sunspot/dsl/query_facet.rb +36 -0
- data/lib/sunspot/dsl/restriction.rb +25 -0
- data/lib/sunspot/dsl/restriction_with_near.rb +160 -0
- data/lib/sunspot/dsl/scope.rb +217 -0
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/dsl/standard_query.rb +123 -0
- data/lib/sunspot/dsl.rb +5 -0
- data/lib/sunspot/field.rb +193 -0
- data/lib/sunspot/field_factory.rb +129 -0
- data/lib/sunspot/indexer.rb +136 -0
- data/lib/sunspot/query/abstract_field_facet.rb +52 -0
- data/lib/sunspot/query/bbox.rb +15 -0
- data/lib/sunspot/query/boost_query.rb +24 -0
- data/lib/sunspot/query/common_query.rb +96 -0
- data/lib/sunspot/query/composite_fulltext.rb +36 -0
- data/lib/sunspot/query/connective.rb +206 -0
- data/lib/sunspot/query/date_field_facet.rb +14 -0
- data/lib/sunspot/query/dismax.rb +132 -0
- data/lib/sunspot/query/field_facet.rb +41 -0
- data/lib/sunspot/query/field_group.rb +36 -0
- data/lib/sunspot/query/filter.rb +38 -0
- data/lib/sunspot/query/function_query.rb +52 -0
- data/lib/sunspot/query/geo.rb +53 -0
- data/lib/sunspot/query/geofilt.rb +16 -0
- data/lib/sunspot/query/highlighting.rb +62 -0
- data/lib/sunspot/query/more_like_this.rb +61 -0
- data/lib/sunspot/query/more_like_this_query.rb +12 -0
- data/lib/sunspot/query/pagination.rb +42 -0
- data/lib/sunspot/query/query_facet.rb +16 -0
- data/lib/sunspot/query/restriction.rb +262 -0
- data/lib/sunspot/query/scope.rb +9 -0
- data/lib/sunspot/query/sort.rb +109 -0
- data/lib/sunspot/query/sort_composite.rb +34 -0
- data/lib/sunspot/query/standard_query.rb +16 -0
- data/lib/sunspot/query/text_field_boost.rb +17 -0
- data/lib/sunspot/query.rb +11 -0
- data/lib/sunspot/schema.rb +151 -0
- data/lib/sunspot/search/abstract_search.rb +281 -0
- 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 +88 -0
- data/lib/sunspot/search/field_group.rb +32 -0
- data/lib/sunspot/search/group.rb +50 -0
- data/lib/sunspot/search/highlight.rb +38 -0
- data/lib/sunspot/search/hit.rb +150 -0
- data/lib/sunspot/search/hit_enumerable.rb +72 -0
- data/lib/sunspot/search/more_like_this_search.rb +31 -0
- data/lib/sunspot/search/paginated_collection.rb +57 -0
- data/lib/sunspot/search/query_facet.rb +67 -0
- data/lib/sunspot/search/standard_search.rb +21 -0
- data/lib/sunspot/search.rb +9 -0
- data/lib/sunspot/session.rb +262 -0
- data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
- data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
- data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
- data/lib/sunspot/session_proxy/multicore_session_proxy.rb +67 -0
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
- data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
- data/lib/sunspot/session_proxy.rb +95 -0
- data/lib/sunspot/setup.rb +350 -0
- data/lib/sunspot/text_field_setup.rb +29 -0
- data/lib/sunspot/type.rb +393 -0
- data/lib/sunspot/util.rb +252 -0
- data/lib/sunspot/version.rb +3 -0
- data/lib/sunspot.rb +579 -0
- data/log/.gitignore +1 -0
- data/pkg/.gitignore +1 -0
- data/script/console +10 -0
- data/spec/api/adapters_spec.rb +33 -0
- data/spec/api/batcher_spec.rb +112 -0
- data/spec/api/binding_spec.rb +50 -0
- data/spec/api/class_set_spec.rb +24 -0
- data/spec/api/hit_enumerable_spec.rb +47 -0
- data/spec/api/indexer/attributes_spec.rb +149 -0
- data/spec/api/indexer/batch_spec.rb +72 -0
- data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
- data/spec/api/indexer/fixed_fields_spec.rb +57 -0
- data/spec/api/indexer/fulltext_spec.rb +43 -0
- data/spec/api/indexer/removal_spec.rb +53 -0
- data/spec/api/indexer/spec_helper.rb +1 -0
- data/spec/api/indexer_spec.rb +14 -0
- data/spec/api/query/advanced_manipulation_examples.rb +35 -0
- data/spec/api/query/connectives_examples.rb +189 -0
- data/spec/api/query/dsl_spec.rb +18 -0
- data/spec/api/query/dynamic_fields_examples.rb +165 -0
- data/spec/api/query/faceting_examples.rb +397 -0
- data/spec/api/query/fulltext_examples.rb +313 -0
- data/spec/api/query/function_spec.rb +79 -0
- data/spec/api/query/geo_examples.rb +68 -0
- data/spec/api/query/group_spec.rb +32 -0
- data/spec/api/query/highlighting_examples.rb +245 -0
- data/spec/api/query/more_like_this_spec.rb +140 -0
- data/spec/api/query/ordering_pagination_examples.rb +116 -0
- data/spec/api/query/scope_examples.rb +275 -0
- data/spec/api/query/spatial_examples.rb +27 -0
- data/spec/api/query/spec_helper.rb +1 -0
- data/spec/api/query/standard_spec.rb +29 -0
- data/spec/api/query/text_field_scoping_examples.rb +30 -0
- data/spec/api/query/types_spec.rb +20 -0
- data/spec/api/search/dynamic_fields_spec.rb +33 -0
- data/spec/api/search/faceting_spec.rb +360 -0
- data/spec/api/search/highlighting_spec.rb +69 -0
- data/spec/api/search/hits_spec.rb +131 -0
- data/spec/api/search/paginated_collection_spec.rb +36 -0
- data/spec/api/search/results_spec.rb +72 -0
- data/spec/api/search/search_spec.rb +23 -0
- data/spec/api/search/spec_helper.rb +1 -0
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
- data/spec/api/session_proxy/spec_helper.rb +9 -0
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
- data/spec/api/session_spec.rb +232 -0
- data/spec/api/spec_helper.rb +3 -0
- data/spec/api/sunspot_spec.rb +29 -0
- data/spec/ext.rb +11 -0
- data/spec/helpers/indexer_helper.rb +17 -0
- data/spec/helpers/integration_helper.rb +8 -0
- data/spec/helpers/mock_session_helper.rb +13 -0
- data/spec/helpers/query_helper.rb +26 -0
- data/spec/helpers/search_helper.rb +68 -0
- data/spec/integration/dynamic_fields_spec.rb +57 -0
- data/spec/integration/faceting_spec.rb +251 -0
- data/spec/integration/field_grouping_spec.rb +66 -0
- data/spec/integration/geospatial_spec.rb +85 -0
- data/spec/integration/highlighting_spec.rb +44 -0
- data/spec/integration/indexing_spec.rb +55 -0
- data/spec/integration/keyword_search_spec.rb +317 -0
- data/spec/integration/local_search_spec.rb +64 -0
- data/spec/integration/more_like_this_spec.rb +43 -0
- data/spec/integration/scoped_search_spec.rb +354 -0
- data/spec/integration/stored_fields_spec.rb +12 -0
- data/spec/integration/test_pagination.rb +43 -0
- data/spec/integration/unicode_spec.rb +15 -0
- data/spec/mocks/adapters.rb +32 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +21 -0
- data/spec/mocks/connection.rb +126 -0
- data/spec/mocks/mock_adapter.rb +30 -0
- data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
- data/spec/mocks/mock_record.rb +52 -0
- data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
- data/spec/mocks/photo.rb +11 -0
- data/spec/mocks/post.rb +86 -0
- data/spec/mocks/super_class.rb +2 -0
- data/spec/mocks/user.rb +13 -0
- data/spec/spec_helper.rb +40 -0
- data/sunspot.gemspec +42 -0
- data/tasks/rdoc.rake +27 -0
- data/tasks/schema.rake +19 -0
- data/tasks/todo.rake +4 -0
- metadata +261 -3
@@ -0,0 +1,68 @@
|
|
1
|
+
module SearchHelper
|
2
|
+
def stub_nil_results
|
3
|
+
connection.response = { 'response' => nil }
|
4
|
+
end
|
5
|
+
|
6
|
+
def stub_full_results(*results)
|
7
|
+
count =
|
8
|
+
if results.last.is_a?(Integer) then results.pop
|
9
|
+
else results.length
|
10
|
+
end
|
11
|
+
docs = results.map do |result|
|
12
|
+
instance = result.delete('instance')
|
13
|
+
result.merge('id' => "#{instance.class.name} #{instance.id}")
|
14
|
+
end
|
15
|
+
response = {
|
16
|
+
'response' => {
|
17
|
+
'docs' => docs,
|
18
|
+
'numFound' => count
|
19
|
+
}
|
20
|
+
}
|
21
|
+
connection.response = response
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
def stub_results(*results)
|
26
|
+
stub_full_results(
|
27
|
+
*results.map do |result|
|
28
|
+
if result.is_a?(Integer)
|
29
|
+
result
|
30
|
+
else
|
31
|
+
{ 'instance' => result }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def stub_facet(name, values)
|
38
|
+
connection.response = {
|
39
|
+
'facet_counts' => {
|
40
|
+
'facet_fields' => {
|
41
|
+
name.to_s => values.to_a.sort_by { |value, count| -count }.flatten
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def stub_date_facet(name, gap, values)
|
48
|
+
connection.response = {
|
49
|
+
'facet_counts' => {
|
50
|
+
'facet_dates' => {
|
51
|
+
name.to_s => { 'gap' => "+#{gap}SECONDS" }.merge(values)
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def stub_query_facet(values)
|
58
|
+
connection.response = { 'facet_counts' => { 'facet_queries' => values } }
|
59
|
+
end
|
60
|
+
|
61
|
+
def facet_values(result, field_name)
|
62
|
+
result.facet(field_name).rows.map { |row| row.value }
|
63
|
+
end
|
64
|
+
|
65
|
+
def facet_counts(result, field_name)
|
66
|
+
result.facet(field_name).rows.map { |row| row.count }
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'dynamic fields' do
|
4
|
+
before :each do
|
5
|
+
Sunspot.remove_all
|
6
|
+
@posts = Post.new(:custom_string => { :cuisine => 'Pizza' }),
|
7
|
+
Post.new(:custom_string => { :cuisine => 'Greek' }),
|
8
|
+
Post.new(:custom_string => { :cuisine => 'Greek' })
|
9
|
+
Sunspot.index!(@posts)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should search for dynamic string field' do
|
13
|
+
Sunspot.search(Post) do
|
14
|
+
dynamic(:custom_string) do
|
15
|
+
with(:cuisine, 'Pizza')
|
16
|
+
end
|
17
|
+
end.results.should == [@posts.first]
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'faceting' do
|
21
|
+
before :each do
|
22
|
+
@search = Sunspot.search(Post) do
|
23
|
+
dynamic :custom_string do
|
24
|
+
facet :cuisine
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return value "value" with count 2' do
|
30
|
+
row = @search.dynamic_facet(:custom_string, :cuisine).rows[0]
|
31
|
+
row.value.should == 'Greek'
|
32
|
+
row.count.should == 2
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should return value "other" with count 1' do
|
36
|
+
row = @search.dynamic_facet(:custom_string, :cuisine).rows[1]
|
37
|
+
row.value.should == 'Pizza'
|
38
|
+
row.count.should == 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should order by dynamic string field ascending' do
|
43
|
+
Sunspot.search(Post) do
|
44
|
+
dynamic :custom_string do
|
45
|
+
order_by :cuisine, :asc
|
46
|
+
end
|
47
|
+
end.results.last.should == @posts.first
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should order by dynamic string field descending' do
|
51
|
+
Sunspot.search(Post) do
|
52
|
+
dynamic :custom_string do
|
53
|
+
order_by :cuisine, :desc
|
54
|
+
end
|
55
|
+
end.results.first.should == @posts.first
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'search faceting' do
|
4
|
+
def self.test_field_type(name, attribute, field, *args)
|
5
|
+
clazz, value1, value2 =
|
6
|
+
if args.length == 2
|
7
|
+
[Post, args.first, args.last]
|
8
|
+
else
|
9
|
+
args
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with field of type #{name}" do
|
13
|
+
before :all do
|
14
|
+
Sunspot.remove_all
|
15
|
+
2.times do
|
16
|
+
Sunspot.index(clazz.new(attribute => value1))
|
17
|
+
end
|
18
|
+
Sunspot.index(clazz.new(attribute => value2))
|
19
|
+
Sunspot.commit
|
20
|
+
end
|
21
|
+
|
22
|
+
before :each do
|
23
|
+
@search = Sunspot.search(clazz) do
|
24
|
+
facet(field)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return value #{value1.inspect} with count 2" do
|
29
|
+
row = @search.facet(field).rows[0]
|
30
|
+
row.value.should == value1
|
31
|
+
row.count.should == 2
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return value #{value2.inspect} with count 1" do
|
35
|
+
row = @search.facet(field).rows[1]
|
36
|
+
row.value.should == value2
|
37
|
+
row.count.should == 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
test_field_type('String', :title, :title, 'Title 1', 'Title 2')
|
43
|
+
test_field_type('Integer', :blog_id, :blog_id, 3, 4)
|
44
|
+
test_field_type('Float', :ratings_average, :average_rating, 2.2, 1.1)
|
45
|
+
test_field_type('Time', :published_at, :published_at, Time.mktime(2008, 02, 17, 17, 45, 04),
|
46
|
+
Time.mktime(2008, 07, 02, 03, 56, 22))
|
47
|
+
test_field_type('Trie Integer', :size, :size, Photo, 3, 4)
|
48
|
+
test_field_type('Float', :average_rating, :average_rating, Photo, 2.2, 1.1)
|
49
|
+
test_field_type('Time', :created_at, :created_at, Photo, Time.mktime(2008, 02, 17, 17, 45, 04),
|
50
|
+
Time.mktime(2008, 07, 02, 03, 56, 22))
|
51
|
+
test_field_type('Boolean', :featured, :featured, true, false)
|
52
|
+
|
53
|
+
context 'facet options' do
|
54
|
+
before :all do
|
55
|
+
Sunspot.remove_all
|
56
|
+
facet_values = %w(zero one two three four)
|
57
|
+
facet_values.each_with_index do |value, i|
|
58
|
+
i.times { Sunspot.index(Post.new(:title => value, :blog_id => 1)) }
|
59
|
+
end
|
60
|
+
Sunspot.index(Post.new(:blog_id => 1))
|
61
|
+
Sunspot.index(Post.new(:title => 'zero', :blog_id => 2))
|
62
|
+
Sunspot.commit
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should limit the number of facet rows' do
|
66
|
+
search = Sunspot.search(Post) do
|
67
|
+
facet :title, :limit => 3
|
68
|
+
end
|
69
|
+
search.facet(:title).should have(3).rows
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should not return zeros by default' do
|
73
|
+
search = Sunspot.search(Post) do
|
74
|
+
with :blog_id, 1
|
75
|
+
facet :title
|
76
|
+
end
|
77
|
+
search.facet(:title).rows.map { |row| row.value }.should_not include('zero')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should return zeros when specified' do
|
81
|
+
search = Sunspot.search(Post) do
|
82
|
+
with :blog_id, 1
|
83
|
+
facet :title, :zeros => true
|
84
|
+
end
|
85
|
+
search.facet(:title).rows.map { |row| row.value }.should include('zero')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should return a specified minimum count' do
|
89
|
+
search = Sunspot.search(Post) do
|
90
|
+
with :blog_id, 1
|
91
|
+
facet :title, :minimum_count => 2
|
92
|
+
end
|
93
|
+
search.facet(:title).rows.map { |row| row.value }.should == %w(four three two)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should order facets lexically' do
|
97
|
+
search = Sunspot.search(Post) do
|
98
|
+
with :blog_id, 1
|
99
|
+
facet :title, :sort => :index
|
100
|
+
end
|
101
|
+
search.facet(:title).rows.map { |row| row.value }.should == %w(four one three two)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should order facets by count' do
|
105
|
+
search = Sunspot.search(Post) do
|
106
|
+
with :blog_id, 1
|
107
|
+
facet :title, :sort => :count
|
108
|
+
end
|
109
|
+
search.facet(:title).rows.map { |row| row.value }.should == %w(four three two one)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should limit facet values by prefix' do
|
113
|
+
search = Sunspot.search(Post) do
|
114
|
+
with :blog_id, 1
|
115
|
+
facet :title, :prefix => 't'
|
116
|
+
end
|
117
|
+
search.facet(:title).rows.map { |row| row.value }.sort.should == %w(three two)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should return :all facet' do
|
121
|
+
search = Sunspot.search(Post) do
|
122
|
+
with :blog_id, 1
|
123
|
+
facet :title, :extra => :any
|
124
|
+
end
|
125
|
+
search.facet(:title).rows.first.value.should == :any
|
126
|
+
search.facet(:title).rows.first.count.should == 10
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should return :none facet' do
|
130
|
+
search = Sunspot.search(Post) do
|
131
|
+
with :blog_id, 1
|
132
|
+
facet :title, :extra => :none
|
133
|
+
end
|
134
|
+
search.facet(:title).rows.first.value.should == :none
|
135
|
+
search.facet(:title).rows.first.count.should == 1
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'gives correct facet count when group == true and truncate == true' do
|
139
|
+
search = Sunspot.search(Post) do
|
140
|
+
group :title do
|
141
|
+
truncate
|
142
|
+
end
|
143
|
+
|
144
|
+
facet :title, :extra => :any
|
145
|
+
end
|
146
|
+
|
147
|
+
# Should be 5 instead of 11
|
148
|
+
search.facet(:title).rows.first.count.should == 5
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'multiselect faceting' do
|
153
|
+
before do
|
154
|
+
Sunspot.remove_all
|
155
|
+
Sunspot.index!(
|
156
|
+
Post.new(:blog_id => 1, :category_ids => [1]),
|
157
|
+
Post.new(:blog_id => 1, :category_ids => [2]),
|
158
|
+
Post.new(:blog_id => 3, :category_ids => [3])
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should exclude filter from faceting' do
|
163
|
+
search = Sunspot.search(Post) do
|
164
|
+
with(:blog_id, 1)
|
165
|
+
category_filter = with(:category_ids, 1)
|
166
|
+
facet(:category_ids, :exclude => category_filter)
|
167
|
+
end
|
168
|
+
search.facet(:category_ids).rows.map { |row| row.value }.to_set.should == Set[1, 2]
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should use facet keys to facet more than once with different exclusions' do
|
172
|
+
search = Sunspot.search(Post) do
|
173
|
+
with(:blog_id, 1)
|
174
|
+
category_filter = with(:category_ids, 1)
|
175
|
+
facet(:category_ids)
|
176
|
+
facet(:category_ids, :exclude => category_filter, :name => :all_category_ids)
|
177
|
+
end
|
178
|
+
search.facet(:category_ids).rows.map { |row| row.value }.should == [1]
|
179
|
+
search.facet(:all_category_ids).rows.map { |row| row.value }.to_set.should == Set[1, 2]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'date facets' do
|
184
|
+
before :all do
|
185
|
+
Sunspot.remove_all
|
186
|
+
time = Time.utc(2009, 7, 8)
|
187
|
+
Sunspot.index!(
|
188
|
+
(0..2).map { |i| Post.new(:published_at => time + i*60*60*16) }
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should return time ranges' do
|
193
|
+
time = Time.utc(2009, 7, 8)
|
194
|
+
search = Sunspot.search(Post) do
|
195
|
+
facet :published_at, :time_range => time..(time + 60*60*24*2), :sort => :count
|
196
|
+
end
|
197
|
+
search.facet(:published_at).rows.first.value.should == (time..(time + 60*60*24))
|
198
|
+
search.facet(:published_at).rows.first.count.should == 2
|
199
|
+
search.facet(:published_at).rows.last.value.should == ((time + 60*60*24)..(time + 60*60*24*2))
|
200
|
+
search.facet(:published_at).rows.last.count.should == 1
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'class facets' do
|
205
|
+
before :all do
|
206
|
+
Sunspot.remove_all
|
207
|
+
Sunspot.index!(Post.new, Post.new, Namespaced::Comment.new)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should return classes' do
|
211
|
+
search = Sunspot.search(Post, Namespaced::Comment) do
|
212
|
+
facet(:class, :sort => :count)
|
213
|
+
end
|
214
|
+
search.facet(:class).rows.first.value.should == Post
|
215
|
+
search.facet(:class).rows.first.count.should == 2
|
216
|
+
search.facet(:class).rows.last.value.should == Namespaced::Comment
|
217
|
+
search.facet(:class).rows.last.count.should == 1
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'query facets' do
|
222
|
+
before :all do
|
223
|
+
Sunspot.remove_all
|
224
|
+
Sunspot.index!(
|
225
|
+
[1.1, 1.2, 3.2, 3.4, 3.9, 4.1].map do |rating|
|
226
|
+
Post.new(:ratings_average => rating)
|
227
|
+
end
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should return specified facets' do
|
232
|
+
search = Sunspot.search(Post) do
|
233
|
+
facet :rating_range, :sort => :count do
|
234
|
+
for rating in [1.0, 2.0, 3.0, 4.0]
|
235
|
+
range = rating..(rating + 1.0)
|
236
|
+
row range do
|
237
|
+
with :average_rating, rating..(rating + 1.0)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
facet = search.facet(:rating_range)
|
243
|
+
facet.rows[0].value.should == (3.0..4.0)
|
244
|
+
facet.rows[0].count.should == 3
|
245
|
+
facet.rows[1].value.should == (1.0..2.0)
|
246
|
+
facet.rows[1].count.should == 2
|
247
|
+
facet.rows[2].value.should == (4.0..5.0)
|
248
|
+
facet.rows[2].count.should == 1
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require File.expand_path("../helpers/search_helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe "field grouping" do
|
5
|
+
before :each do
|
6
|
+
Sunspot.remove_all
|
7
|
+
|
8
|
+
@posts = [
|
9
|
+
Post.new(:title => "Title1", :ratings_average => 4),
|
10
|
+
Post.new(:title => "Title1", :ratings_average => 5),
|
11
|
+
Post.new(:title => "Title2", :ratings_average => 3)
|
12
|
+
]
|
13
|
+
|
14
|
+
Sunspot.index!(*@posts)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "allows grouping by a field" do
|
18
|
+
search = Sunspot.search(Post) do
|
19
|
+
group :title
|
20
|
+
end
|
21
|
+
|
22
|
+
search.group(:title).groups.should include { |g| g.value == "Title1" }
|
23
|
+
search.group(:title).groups.should include { |g| g.value == "Title2" }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "provides access to the number of matches before grouping" do
|
27
|
+
search = Sunspot.search(Post) do
|
28
|
+
group :title
|
29
|
+
end
|
30
|
+
|
31
|
+
search.group(:title).matches.should == @posts.length
|
32
|
+
end
|
33
|
+
|
34
|
+
it "allows grouping by multiple fields" do
|
35
|
+
search = Sunspot.search(Post) do
|
36
|
+
group :title, :sort_title
|
37
|
+
end
|
38
|
+
|
39
|
+
search.group(:title).groups.should_not be_empty
|
40
|
+
search.group(:sort_title).groups.should_not be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it "allows specification of the number of documents per group" do
|
44
|
+
search = Sunspot.search(Post) do
|
45
|
+
group :title do
|
46
|
+
limit 2
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
|
51
|
+
title1_group.hits.length.should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it "allows specification of the sort within groups" do
|
55
|
+
search = Sunspot.search(Post) do
|
56
|
+
group :title do
|
57
|
+
order_by(:average_rating, :desc)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
highest_ranked_post = @posts.sort_by { |p| -p.ratings_average }.first
|
62
|
+
|
63
|
+
title1_group = search.group(:title).groups.detect { |g| g.value == "Title1" }
|
64
|
+
title1_group.hits.first.primary_key.to_i.should == highest_ranked_post.id
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "geospatial search" do
|
4
|
+
describe "filtering by radius" do
|
5
|
+
before :all do
|
6
|
+
Sunspot.remove_all
|
7
|
+
|
8
|
+
@post = Post.new(:title => "Howdy",
|
9
|
+
:coordinates => Sunspot::Util::Coordinates.new(32, -68))
|
10
|
+
Sunspot.index!(@post)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "matches posts within the radius" do
|
14
|
+
results = Sunspot.search(Post) {
|
15
|
+
with(:coordinates_new).in_radius(32, -68, 1)
|
16
|
+
}.results
|
17
|
+
|
18
|
+
results.should include(@post)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "filters out posts not in the radius" do
|
22
|
+
results = Sunspot.search(Post) {
|
23
|
+
with(:coordinates_new).in_radius(33, -68, 1)
|
24
|
+
}.results
|
25
|
+
|
26
|
+
results.should_not include(@post)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "filtering by bounding box" do
|
31
|
+
before :all do
|
32
|
+
Sunspot.remove_all
|
33
|
+
|
34
|
+
@post = Post.new(:title => "Howdy",
|
35
|
+
:coordinates => Sunspot::Util::Coordinates.new(32, -68))
|
36
|
+
Sunspot.index!(@post)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "matches post within the bounding box" do
|
40
|
+
results = Sunspot.search(Post) {
|
41
|
+
with(:coordinates_new).in_bounding_box [31, -69], [33, -67]
|
42
|
+
}.results
|
43
|
+
|
44
|
+
results.should include(@post)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "filters out posts not in the bounding box" do
|
48
|
+
results = Sunspot.search(Post) {
|
49
|
+
with(:coordinates_new).in_bounding_box [20, -70], [21, -69]
|
50
|
+
}.results
|
51
|
+
|
52
|
+
results.should_not include(@post)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "ordering by geodist" do
|
57
|
+
before :all do
|
58
|
+
Sunspot.remove_all
|
59
|
+
|
60
|
+
@posts = [
|
61
|
+
Post.new(:title => "Howdy", :coordinates => Sunspot::Util::Coordinates.new(34, -68)),
|
62
|
+
Post.new(:title => "Howdy", :coordinates => Sunspot::Util::Coordinates.new(33, -68)),
|
63
|
+
Post.new(:title => "Howdy", :coordinates => Sunspot::Util::Coordinates.new(32, -68))
|
64
|
+
]
|
65
|
+
|
66
|
+
Sunspot.index!(@posts)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "orders posts by distance ascending" do
|
70
|
+
results = Sunspot.search(Post) {
|
71
|
+
order_by_geodist(:coordinates_new, 32, -68)
|
72
|
+
}.results
|
73
|
+
|
74
|
+
results.should == @posts.reverse
|
75
|
+
end
|
76
|
+
|
77
|
+
it "orders posts by distance descending" do
|
78
|
+
results = Sunspot.search(Post) {
|
79
|
+
order_by_geodist(:coordinates_new, 32, -68, :desc)
|
80
|
+
}.results
|
81
|
+
|
82
|
+
results.should == @posts
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'keyword highlighting' do
|
4
|
+
before :all do
|
5
|
+
@posts = []
|
6
|
+
@posts << Post.new(:body => 'And the fox laughed')
|
7
|
+
@posts << Post.new(:body => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit', :blog_id => 1)
|
8
|
+
@posts << Post.new(:body => 'Lorem ipsum dolor sit amet', :title => 'consectetur adipiscing elit', :blog_id => 1)
|
9
|
+
Sunspot.index!(*@posts)
|
10
|
+
@search_result = Sunspot.search(Post) { keywords 'fox', :highlight => true }
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should include highlights in the results' do
|
14
|
+
@search_result.hits.first.highlights.length.should == 1
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return formatted highlight fragments' do
|
18
|
+
@search_result.hits.first.highlights(:body).first.format.should == 'And the <em>fox</em> laughed'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be empty for non-keyword searches' do
|
22
|
+
search_result = Sunspot.search(Post){ with :blog_id, 1 }
|
23
|
+
search_result.hits.first.highlights.should be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should process multiple keyword request on different fields with highlights correctly" do
|
27
|
+
search_results = nil
|
28
|
+
lambda do
|
29
|
+
search_results = Sunspot.search(Post) do
|
30
|
+
keywords 'Lorem ipsum', :fields => [:body] do
|
31
|
+
highlight :body
|
32
|
+
end
|
33
|
+
keywords 'consectetur', :fields => [:title] do
|
34
|
+
highlight :title
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end.should_not raise_error(RSolr::Error::Http)
|
38
|
+
search_results.results.length.should eq(1)
|
39
|
+
search_results.results.first.should eq(@posts.last)
|
40
|
+
# this one might be a Solr bug, therefore not related to Sunspot itself
|
41
|
+
# search_results.hits.first.highlights.should_not be_empty
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'indexing' do
|
4
|
+
it 'should index non-multivalued field with newlines' do
|
5
|
+
lambda do
|
6
|
+
Sunspot.index!(Post.new(:title => "A\nTitle"))
|
7
|
+
end.should_not raise_error
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should correctly remove by model instance' do
|
11
|
+
post = Post.new(:title => 'test post')
|
12
|
+
Sunspot.index!(post)
|
13
|
+
Sunspot.remove!(post)
|
14
|
+
Sunspot.search(Post) { with(:title, 'test post') }.results.should be_empty
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should correctly delete by ID' do
|
18
|
+
post = Post.new(:title => 'test post')
|
19
|
+
Sunspot.index!(post)
|
20
|
+
Sunspot.remove_by_id!(Post, post.id)
|
21
|
+
Sunspot.search(Post) { with(:title, 'test post') }.results.should be_empty
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'removes documents by query' do
|
25
|
+
Sunspot.remove_all!
|
26
|
+
posts = [Post.new(:title => 'birds'), Post.new(:title => 'monkeys')]
|
27
|
+
Sunspot.index!(posts)
|
28
|
+
Sunspot.remove! do
|
29
|
+
with(:title, 'birds')
|
30
|
+
end
|
31
|
+
Sunspot.search(Post).should have(2).results
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
describe "in batches" do
|
36
|
+
let(:post_1) { Post.new :title => 'A tittle' }
|
37
|
+
let(:post_2) { Post.new :title => 'Another title' }
|
38
|
+
|
39
|
+
describe "nested" do
|
40
|
+
let(:a_nested_batch) do
|
41
|
+
Sunspot.batch do
|
42
|
+
Sunspot.index post_1
|
43
|
+
|
44
|
+
Sunspot.batch do
|
45
|
+
Sunspot.index post_2
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does not fail" do
|
51
|
+
expect { a_nested_batch }.to_not raise_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|