sunspot 2.0.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/spec/api/sunspot_spec.rb
CHANGED
@@ -7,8 +7,8 @@ describe Sunspot do
|
|
7
7
|
Sunspot.setup(User) do
|
8
8
|
text :name
|
9
9
|
end
|
10
|
-
Sunspot.searchable.
|
11
|
-
Sunspot.searchable.
|
10
|
+
expect(Sunspot.searchable).not_to be_empty
|
11
|
+
expect(Sunspot.searchable).to include(User)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -16,14 +16,17 @@ describe Sunspot do
|
|
16
16
|
it "should reset current session" do
|
17
17
|
old_session = Sunspot.send(:session)
|
18
18
|
Sunspot.reset!(true)
|
19
|
-
Sunspot.send(:session).
|
19
|
+
expect(Sunspot.send(:session)).not_to eq(old_session)
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should keep keep configuration if specified" do
|
23
23
|
Sunspot.config.solr.url = "http://localhost:9999/path/solr"
|
24
24
|
config_before_reset = Sunspot.config
|
25
25
|
Sunspot.reset!(true)
|
26
|
-
Sunspot.config.
|
26
|
+
expect(Sunspot.config).to eq(config_before_reset)
|
27
|
+
|
28
|
+
# Restore sunspot config after test
|
29
|
+
Sunspot.reset!(false)
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
@@ -1,8 +1,18 @@
|
|
1
1
|
module IntegrationHelper
|
2
2
|
def self.included(base)
|
3
3
|
base.before(:all) do
|
4
|
-
Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr'
|
4
|
+
Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr/default'
|
5
|
+
Sunspot.config.solr.update_format = ENV['UPDATE_FORMAT'].to_sym if ENV['UPDATE_FORMAT']
|
5
6
|
Sunspot.reset!(true)
|
6
7
|
end
|
7
8
|
end
|
9
|
+
|
10
|
+
def featured_for_posts(method, param, negated = false)
|
11
|
+
with_method = negated ? :without : :with
|
12
|
+
param = date_ranges[param] if param.is_a? String
|
13
|
+
|
14
|
+
Sunspot.search(Post) do
|
15
|
+
send(with_method, :featured_for).send(method, param)
|
16
|
+
end.results
|
17
|
+
end
|
8
18
|
end
|
@@ -11,7 +11,7 @@ module QueryHelper
|
|
11
11
|
def subqueries(param)
|
12
12
|
q = connection.searches.last[:q]
|
13
13
|
subqueries = []
|
14
|
-
subqueries = q.scan(%r(_query_:"\{!
|
14
|
+
subqueries = q.scan(%r(_query_:"\{!edismax (.*?)\}(.*?)"))
|
15
15
|
subqueries.map do |subquery|
|
16
16
|
params = {}
|
17
17
|
subquery[0].scan(%r((\S+?)='(.+?)')) do |key, value|
|
@@ -54,6 +54,28 @@ module SearchHelper
|
|
54
54
|
}
|
55
55
|
end
|
56
56
|
|
57
|
+
def stub_stats(name, values)
|
58
|
+
connection.response = {
|
59
|
+
'stats' => {
|
60
|
+
'stats_fields' => {
|
61
|
+
name.to_s => { :facets => {} }.merge(values)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def stub_stats_facets(name, facets)
|
68
|
+
connection.response = {
|
69
|
+
'stats' => {
|
70
|
+
'stats_fields' => {
|
71
|
+
name.to_s => {
|
72
|
+
'facets' => facets
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
57
79
|
def stub_query_facet(values)
|
58
80
|
connection.response = { 'facet_counts' => { 'facet_queries' => values } }
|
59
81
|
end
|
@@ -65,4 +87,12 @@ module SearchHelper
|
|
65
87
|
def facet_counts(result, field_name)
|
66
88
|
result.facet(field_name).rows.map { |row| row.count }
|
67
89
|
end
|
90
|
+
|
91
|
+
def stats_facet_values(result, field_name, facet_name)
|
92
|
+
result.stats(field_name).facet(facet_name).rows.map(&:value)
|
93
|
+
end
|
94
|
+
|
95
|
+
def stats_facet_stats(result, field_name, facet_name, value)
|
96
|
+
result.stats(field_name).facet(facet_name).rows.find { |r| r.value == value }
|
97
|
+
end
|
68
98
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'atomic updates' do
|
4
|
+
before :all do
|
5
|
+
Sunspot.remove_all
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_hit(hit, values = {})
|
9
|
+
values.each do |field, value|
|
10
|
+
stored = hit.stored(field)
|
11
|
+
expect(stored).to eq(value), "expected #{value.inspect}, but got #{stored.inspect} for field '#{field}'"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def find_indexed_post(id)
|
16
|
+
hit = Sunspot.search(Post).hits.find{ |h| h.primary_key.to_i == id }
|
17
|
+
expect(hit).not_to be_nil
|
18
|
+
hit
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should update single record fields one by one' do
|
22
|
+
post = Post.new(title: 'A Title', featured: true)
|
23
|
+
Sunspot.index!(post)
|
24
|
+
|
25
|
+
validate_hit(find_indexed_post(post.id), title: post.title, featured: post.featured)
|
26
|
+
|
27
|
+
Sunspot.atomic_update!(Post, post.id => {title: 'A New Title'})
|
28
|
+
validate_hit(find_indexed_post(post.id), title: 'A New Title', featured: true)
|
29
|
+
|
30
|
+
Sunspot.atomic_update!(Post, post.id => {featured: false})
|
31
|
+
validate_hit(find_indexed_post(post.id), title: 'A New Title', featured: false)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should update fields for multiple records' do
|
35
|
+
post1 = Post.new(title: 'A First Title', featured: true)
|
36
|
+
post2 = Post.new(title: 'A Second Title', featured: false)
|
37
|
+
Sunspot.index!(post1, post2)
|
38
|
+
|
39
|
+
validate_hit(find_indexed_post(post1.id), title: post1.title, featured: post1.featured)
|
40
|
+
validate_hit(find_indexed_post(post2.id), title: post2.title, featured: post2.featured)
|
41
|
+
|
42
|
+
Sunspot.atomic_update!(Post, post1.id => {title: 'A New Title'}, post2.id => {featured: true})
|
43
|
+
validate_hit(find_indexed_post(post1.id), title: 'A New Title', featured: true)
|
44
|
+
validate_hit(find_indexed_post(post2.id), title: 'A Second Title', featured: true)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should clear field value properly' do
|
48
|
+
post = Post.new(title: 'A Title', tags: %w(tag1 tag2), featured: true)
|
49
|
+
Sunspot.index!(post)
|
50
|
+
validate_hit(find_indexed_post(post.id), title: post.title, tag_list: post.tags, featured: true)
|
51
|
+
|
52
|
+
Sunspot.atomic_update!(Post, post.id => {tag_list: []})
|
53
|
+
validate_hit(find_indexed_post(post.id), title: post.title, tag_list: nil, featured: true)
|
54
|
+
|
55
|
+
Sunspot.atomic_update!(Post, post.id => {featured: nil})
|
56
|
+
validate_hit(find_indexed_post(post.id), title: post.title, tag_list: nil, featured: nil)
|
57
|
+
end
|
58
|
+
end
|
@@ -1,57 +1,68 @@
|
|
1
1
|
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
2
|
|
3
|
-
|
3
|
+
shared_examples 'dynamic fields' do
|
4
4
|
before :each do
|
5
5
|
Sunspot.remove_all
|
6
|
-
@posts = Post.new(
|
7
|
-
Post.new(
|
8
|
-
Post.new(
|
6
|
+
@posts = Post.new(field_name => { :cuisine => 'Pizza' }),
|
7
|
+
Post.new(field_name => { :cuisine => 'Greek' }),
|
8
|
+
Post.new(field_name => { :cuisine => 'Greek' })
|
9
9
|
Sunspot.index!(@posts)
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should search for dynamic string field' do
|
13
|
-
Sunspot.search(Post) do
|
14
|
-
dynamic(
|
13
|
+
expect(Sunspot.search(Post) do
|
14
|
+
dynamic(field_name) do
|
15
15
|
with(:cuisine, 'Pizza')
|
16
16
|
end
|
17
|
-
end.results.
|
17
|
+
end.results).to eq([@posts.first])
|
18
18
|
end
|
19
19
|
|
20
20
|
describe 'faceting' do
|
21
21
|
before :each do
|
22
22
|
@search = Sunspot.search(Post) do
|
23
|
-
dynamic
|
23
|
+
dynamic field_name do
|
24
24
|
facet :cuisine
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should return value "value" with count 2' do
|
30
|
-
row = @search.dynamic_facet(
|
31
|
-
row.value.
|
32
|
-
row.count.
|
30
|
+
row = @search.dynamic_facet(field_name, :cuisine).rows[0]
|
31
|
+
expect(row.value).to eq('Greek')
|
32
|
+
expect(row.count).to eq(2)
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'should return value "other" with count 1' do
|
36
|
-
row = @search.dynamic_facet(
|
37
|
-
row.value.
|
38
|
-
row.count.
|
36
|
+
row = @search.dynamic_facet(field_name, :cuisine).rows[1]
|
37
|
+
expect(row.value).to eq('Pizza')
|
38
|
+
expect(row.count).to eq(1)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'should order by dynamic string field ascending' do
|
43
|
-
Sunspot.search(Post) do
|
44
|
-
dynamic
|
43
|
+
expect(Sunspot.search(Post) do
|
44
|
+
dynamic field_name do
|
45
45
|
order_by :cuisine, :asc
|
46
46
|
end
|
47
|
-
end.results.last.
|
47
|
+
end.results.last).to eq(@posts.first)
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'should order by dynamic string field descending' do
|
51
|
-
Sunspot.search(Post) do
|
52
|
-
dynamic
|
51
|
+
expect(Sunspot.search(Post) do
|
52
|
+
dynamic field_name do
|
53
53
|
order_by :cuisine, :desc
|
54
54
|
end
|
55
|
-
end.results.first.
|
55
|
+
end.results.first).to eq(@posts.first)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "default separator" do
|
60
|
+
it_behaves_like "dynamic fields" do
|
61
|
+
let(:field_name) { :custom_string }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
describe "custom separator" do
|
65
|
+
it_behaves_like "dynamic fields" do
|
66
|
+
let(:field_name) { :custom_underscored_string }
|
56
67
|
end
|
57
68
|
end
|
@@ -27,14 +27,14 @@ describe 'search faceting' do
|
|
27
27
|
|
28
28
|
it "should return value #{value1.inspect} with count 2" do
|
29
29
|
row = @search.facet(field).rows[0]
|
30
|
-
row.value.
|
31
|
-
row.count.
|
30
|
+
expect(row.value).to eq(value1)
|
31
|
+
expect(row.count).to eq(2)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should return value #{value2.inspect} with count 1" do
|
35
35
|
row = @search.facet(field).rows[1]
|
36
|
-
row.value.
|
37
|
-
row.count.
|
36
|
+
expect(row.value).to eq(value2)
|
37
|
+
expect(row.count).to eq(1)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -66,7 +66,7 @@ describe 'search faceting' do
|
|
66
66
|
search = Sunspot.search(Post) do
|
67
67
|
facet :title, :limit => 3
|
68
68
|
end
|
69
|
-
search.facet(:title).
|
69
|
+
expect(search.facet(:title).rows.size).to eq(3)
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'should not return zeros by default' do
|
@@ -74,7 +74,7 @@ describe 'search faceting' do
|
|
74
74
|
with :blog_id, 1
|
75
75
|
facet :title
|
76
76
|
end
|
77
|
-
search.facet(:title).rows.map { |row| row.value }.
|
77
|
+
expect(search.facet(:title).rows.map { |row| row.value }).not_to include('zero')
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'should return zeros when specified' do
|
@@ -82,14 +82,14 @@ describe 'search faceting' do
|
|
82
82
|
with :blog_id, 1
|
83
83
|
facet :title, :zeros => true
|
84
84
|
end
|
85
|
-
search.facet(:title).rows.map { |row| row.value }.
|
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
|
91
91
|
end
|
92
|
-
search.facet(:title).rows.map { |row| row.value }.
|
92
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(one zero))
|
93
93
|
end
|
94
94
|
|
95
95
|
it 'should return a specified minimum count' do
|
@@ -97,7 +97,7 @@ describe 'search faceting' do
|
|
97
97
|
with :blog_id, 1
|
98
98
|
facet :title, :minimum_count => 2
|
99
99
|
end
|
100
|
-
search.facet(:title).rows.map { |row| row.value }.
|
100
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two))
|
101
101
|
end
|
102
102
|
|
103
103
|
it 'should order facets lexically' do
|
@@ -105,7 +105,7 @@ describe 'search faceting' do
|
|
105
105
|
with :blog_id, 1
|
106
106
|
facet :title, :sort => :index
|
107
107
|
end
|
108
|
-
search.facet(:title).rows.map { |row| row.value }.
|
108
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four one three two))
|
109
109
|
end
|
110
110
|
|
111
111
|
it 'should order facets by count' do
|
@@ -113,7 +113,7 @@ describe 'search faceting' do
|
|
113
113
|
with :blog_id, 1
|
114
114
|
facet :title, :sort => :count
|
115
115
|
end
|
116
|
-
search.facet(:title).rows.map { |row| row.value }.
|
116
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
|
117
117
|
end
|
118
118
|
|
119
119
|
it 'should limit facet values by prefix' do
|
@@ -121,7 +121,7 @@ describe 'search faceting' do
|
|
121
121
|
with :blog_id, 1
|
122
122
|
facet :title, :prefix => 't'
|
123
123
|
end
|
124
|
-
search.facet(:title).rows.map { |row| row.value }.sort.
|
124
|
+
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
|
125
125
|
end
|
126
126
|
|
127
127
|
it 'should return :all facet' do
|
@@ -129,8 +129,8 @@ describe 'search faceting' do
|
|
129
129
|
with :blog_id, 1
|
130
130
|
facet :title, :extra => :any
|
131
131
|
end
|
132
|
-
search.facet(:title).rows.first.value.
|
133
|
-
search.facet(:title).rows.first.count.
|
132
|
+
expect(search.facet(:title).rows.first.value).to eq(:any)
|
133
|
+
expect(search.facet(:title).rows.first.count).to eq(10)
|
134
134
|
end
|
135
135
|
|
136
136
|
it 'should return :none facet' do
|
@@ -138,8 +138,8 @@ describe 'search faceting' do
|
|
138
138
|
with :blog_id, 1
|
139
139
|
facet :title, :extra => :none
|
140
140
|
end
|
141
|
-
search.facet(:title).rows.first.value.
|
142
|
-
search.facet(:title).rows.first.count.
|
141
|
+
expect(search.facet(:title).rows.first.value).to eq(:none)
|
142
|
+
expect(search.facet(:title).rows.first.count).to eq(1)
|
143
143
|
end
|
144
144
|
|
145
145
|
it 'gives correct facet count when group == true and truncate == true' do
|
@@ -152,10 +152,140 @@ describe 'search faceting' do
|
|
152
152
|
end
|
153
153
|
|
154
154
|
# Should be 5 instead of 11
|
155
|
-
search.facet(:title).rows.first.count.
|
155
|
+
expect(search.facet(:title).rows.first.count).to eq(5)
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
+
context 'json facet options' do
|
160
|
+
before :all do
|
161
|
+
Sunspot.remove_all
|
162
|
+
facet_values = %w(zero one two three four)
|
163
|
+
facet_values.each_with_index do |value, i|
|
164
|
+
i.times { Sunspot.index(Post.new(:title => value, :blog_id => 1)) }
|
165
|
+
end
|
166
|
+
Sunspot.index(Post.new(:blog_id => 1))
|
167
|
+
Sunspot.index(Post.new(:title => 'zero', :blog_id => 2))
|
168
|
+
Sunspot.commit
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should return indexed elements' do
|
172
|
+
search = Sunspot.search(Post) do
|
173
|
+
json_facet(:title)
|
174
|
+
end
|
175
|
+
expect(search.facet(:title).rows.size).to eq(5)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should limit the number of facet rows' do
|
179
|
+
search = Sunspot.search(Post) do
|
180
|
+
json_facet :title, :limit => 3
|
181
|
+
end
|
182
|
+
expect(search.facet(:title).rows.size).to eq(3)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should not return zeros by default' do
|
186
|
+
search = Sunspot.search(Post) do
|
187
|
+
with :blog_id, 1
|
188
|
+
json_facet :title
|
189
|
+
end
|
190
|
+
expect(search.facet(:title).rows.map { |row| row.value }).not_to include('zero')
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should return a specified minimum count' do
|
194
|
+
search = Sunspot.search(Post) do
|
195
|
+
with :blog_id, 1
|
196
|
+
json_facet :title, :minimum_count => 2
|
197
|
+
end
|
198
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two))
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should order facets lexically' do
|
202
|
+
search = Sunspot.search(Post) do
|
203
|
+
with :blog_id, 1
|
204
|
+
json_facet :title, :sort => :index
|
205
|
+
end
|
206
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four one three two))
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should order facets by count' do
|
210
|
+
search = Sunspot.search(Post) do
|
211
|
+
with :blog_id, 1
|
212
|
+
json_facet :title, :sort => :count
|
213
|
+
end
|
214
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should limit facet values by prefix' do
|
218
|
+
search = Sunspot.search(Post) do
|
219
|
+
with :blog_id, 1
|
220
|
+
json_facet :title, :prefix => 't'
|
221
|
+
end
|
222
|
+
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'nested json facet' do
|
228
|
+
before :all do
|
229
|
+
Sunspot.remove_all
|
230
|
+
facet_values = %w(zero one two three four)
|
231
|
+
nested_facet_values = %w(alfa bravo charlie delta)
|
232
|
+
|
233
|
+
facet_values.each do |value|
|
234
|
+
nested_facet_values.each do |v2|
|
235
|
+
Sunspot.index(Post.new(:title => value, :author_name => v2, :blog_id => 1))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
0.upto(9) { |i| Sunspot.index(Post.new(:title => 'zero', :author_name => "another#{i}", :blog_id => 1)) }
|
240
|
+
|
241
|
+
Sunspot.commit
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should get nested' do
|
245
|
+
search = Sunspot.search(Post) do
|
246
|
+
json_facet(:title, nested: { field: :author_name } )
|
247
|
+
end
|
248
|
+
expect(search.facet(:title).rows.first.nested.size).to eq(4)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'without limit take the first 10' do
|
252
|
+
search = Sunspot.search(Post) do
|
253
|
+
json_facet(:title, nested: { field: :author_name } )
|
254
|
+
end
|
255
|
+
expect(search.facet(:title).rows.last.nested.size).to eq(10)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'without limit' do
|
259
|
+
search = Sunspot.search(Post) do
|
260
|
+
json_facet(:title, nested: { field: :author_name, limit: -1 } )
|
261
|
+
end
|
262
|
+
expect(search.facet(:title).rows.last.nested.size).to eq(14)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'works with distinct' do
|
266
|
+
search = Sunspot.search(Post) do
|
267
|
+
json_facet(:title, nested: { field: :author_name, distinct: { strategy: :unique } } )
|
268
|
+
end
|
269
|
+
expect(search.facet(:title).rows.first.nested.map(&:count).uniq.size).to eq(1)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should limit the nested facet' do
|
273
|
+
search = Sunspot.search(Post) do
|
274
|
+
json_facet(:title, nested: { field: :author_name, limit: 2 } )
|
275
|
+
end
|
276
|
+
expect(search.facet(:title).rows.first.nested.size).to eq(2)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should work nested of nested' do
|
280
|
+
search = Sunspot.search(Post) do
|
281
|
+
json_facet(:title, nested: { field: :author_name, nested: { field: :title } } )
|
282
|
+
end
|
283
|
+
expect(search.facet(:title).rows.first.nested.first.nested.size).to eq(1)
|
284
|
+
expect(search.facet(:title).rows.first.nested.first.nested.first.nested).to eq(nil)
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
159
289
|
context 'prefix escaping' do
|
160
290
|
before do
|
161
291
|
Sunspot.remove_all
|
@@ -170,7 +300,7 @@ describe 'search faceting' do
|
|
170
300
|
with :blog_id, 1
|
171
301
|
facet :title, :prefix => 'title '
|
172
302
|
end
|
173
|
-
search.facet(:title).rows.map { |row| row.value }.sort.
|
303
|
+
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(["title with spaces 1", "title with spaces 2"])
|
174
304
|
end
|
175
305
|
|
176
306
|
it 'should limit facet values by a prefix with slashes' do
|
@@ -178,7 +308,7 @@ describe 'search faceting' do
|
|
178
308
|
with :blog_id, 1
|
179
309
|
facet :title, :prefix => 'title/'
|
180
310
|
end
|
181
|
-
search.facet(:title).rows.map { |row| row.value }.sort.
|
311
|
+
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(["title/with/slashes/1", "title/with/slashes/2"])
|
182
312
|
end
|
183
313
|
end
|
184
314
|
|
@@ -199,7 +329,7 @@ describe 'search faceting' do
|
|
199
329
|
category_filter = with(:category_ids, 1)
|
200
330
|
facet(:category_ids, :exclude => category_filter)
|
201
331
|
end
|
202
|
-
search.facet(:category_ids).rows.map { |row| row.value }.to_set.
|
332
|
+
expect(search.facet(:category_ids).rows.map { |row| row.value }.to_set).to eq(Set[1, 2])
|
203
333
|
end
|
204
334
|
|
205
335
|
it 'should use facet keys to facet more than once with different exclusions' do
|
@@ -209,8 +339,8 @@ describe 'search faceting' do
|
|
209
339
|
facet(:category_ids)
|
210
340
|
facet(:category_ids, :exclude => category_filter, :name => :all_category_ids)
|
211
341
|
end
|
212
|
-
search.facet(:category_ids).rows.map { |row| row.value }.
|
213
|
-
search.facet(:all_category_ids).rows.map { |row| row.value }.to_set.
|
342
|
+
expect(search.facet(:category_ids).rows.map { |row| row.value }).to eq([1])
|
343
|
+
expect(search.facet(:all_category_ids).rows.map { |row| row.value }.to_set).to eq(Set[1, 2])
|
214
344
|
end
|
215
345
|
end
|
216
346
|
|
@@ -228,7 +358,7 @@ describe 'search faceting' do
|
|
228
358
|
end
|
229
359
|
end
|
230
360
|
end
|
231
|
-
search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set.
|
361
|
+
expect(search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1], [:category_2, 1]])
|
232
362
|
end
|
233
363
|
|
234
364
|
it 'should use facet keys to facet more than once with different exclusions' do
|
@@ -253,12 +383,63 @@ describe 'search faceting' do
|
|
253
383
|
end
|
254
384
|
end
|
255
385
|
end
|
256
|
-
search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set.
|
257
|
-
search.facet(:all_category_ids).rows.map { |row| [row.value, row.count] }.to_set.
|
386
|
+
expect(search.facet(:category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1]])
|
387
|
+
expect(search.facet(:all_category_ids).rows.map { |row| [row.value, row.count] }.to_set).to eq(Set[[:category_1, 1], [:category_2, 1]])
|
258
388
|
end
|
259
389
|
end
|
260
390
|
end
|
261
391
|
|
392
|
+
context 'distinct field facets' do
|
393
|
+
before :all do
|
394
|
+
Sunspot.remove_all
|
395
|
+
|
396
|
+
Sunspot.index!(
|
397
|
+
(0..5).map { |i| Post.new(:blog_id => i, :title => 'title') }
|
398
|
+
)
|
399
|
+
|
400
|
+
0.upto(3) { |i| Sunspot.index(Post.new(:blog_id => i, :title => 'title')) }
|
401
|
+
|
402
|
+
Sunspot.index!(Post.new(:blog_id => 4, :title => 'other title'))
|
403
|
+
Sunspot.index!(Post.new(:blog_id => 5, :title => 'other title'))
|
404
|
+
|
405
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
|
406
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
|
407
|
+
|
408
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
|
409
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'should return unique indexed elements for a field' do
|
413
|
+
search = Sunspot.search(Post) do
|
414
|
+
json_facet(:blog_id, distinct: { strategy: :unique })
|
415
|
+
end
|
416
|
+
|
417
|
+
expect(search.facet(:blog_id).rows.size).to eq(7)
|
418
|
+
expect(search.facet(:blog_id).rows.map(&:count).uniq.size).to eq(1)
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'should return unique indexed elements for a field and facet on a field' do
|
422
|
+
search = Sunspot.search(Post) do
|
423
|
+
json_facet(:blog_id, distinct: { group_by: :title, strategy: :unique })
|
424
|
+
end
|
425
|
+
|
426
|
+
expect(search.facet(:blog_id).rows.size).to eq(2)
|
427
|
+
expect(search.facet(:blog_id).rows[0].count).to eq(3)
|
428
|
+
expect(search.facet(:blog_id).rows[1].count).to eq(7)
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'should return unique indexed elements for a field and facet on a field with hll' do
|
432
|
+
search = Sunspot.search(Post) do
|
433
|
+
json_facet(:blog_id, distinct: { group_by: :title, strategy: :hll })
|
434
|
+
end
|
435
|
+
|
436
|
+
expect(search.facet(:blog_id).rows.size).to eq(2)
|
437
|
+
expect(search.facet(:blog_id).rows[0].count).to eq(3)
|
438
|
+
expect(search.facet(:blog_id).rows[1].count).to eq(7)
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
|
262
443
|
context 'date facets' do
|
263
444
|
before :all do
|
264
445
|
Sunspot.remove_all
|
@@ -273,11 +454,43 @@ describe 'search faceting' do
|
|
273
454
|
search = Sunspot.search(Post) do
|
274
455
|
facet :published_at, :time_range => time..(time + 60*60*24*2), :sort => :count
|
275
456
|
end
|
276
|
-
search.facet(:published_at).rows.first.value.
|
277
|
-
search.facet(:published_at).rows.first.count.
|
278
|
-
search.facet(:published_at).rows.last.value.
|
279
|
-
search.facet(:published_at).rows.last.count.
|
457
|
+
expect(search.facet(:published_at).rows.first.value).to eq(time..(time + 60*60*24))
|
458
|
+
expect(search.facet(:published_at).rows.first.count).to eq(2)
|
459
|
+
expect(search.facet(:published_at).rows.last.value).to eq((time + 60*60*24)..(time + 60*60*24*2))
|
460
|
+
expect(search.facet(:published_at).rows.last.count).to eq(1)
|
280
461
|
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
|
+
|
281
494
|
end
|
282
495
|
|
283
496
|
context 'class facets' do
|
@@ -290,10 +503,10 @@ describe 'search faceting' do
|
|
290
503
|
search = Sunspot.search(Post, Namespaced::Comment) do
|
291
504
|
facet(:class, :sort => :count)
|
292
505
|
end
|
293
|
-
search.facet(:class).rows.first.value.
|
294
|
-
search.facet(:class).rows.first.count.
|
295
|
-
search.facet(:class).rows.last.value.
|
296
|
-
search.facet(:class).rows.last.count.
|
506
|
+
expect(search.facet(:class).rows.first.value).to eq(Post)
|
507
|
+
expect(search.facet(:class).rows.first.count).to eq(2)
|
508
|
+
expect(search.facet(:class).rows.last.value).to eq(Namespaced::Comment)
|
509
|
+
expect(search.facet(:class).rows.last.count).to eq(1)
|
297
510
|
end
|
298
511
|
end
|
299
512
|
|
@@ -319,12 +532,12 @@ describe 'search faceting' do
|
|
319
532
|
end
|
320
533
|
end
|
321
534
|
facet = search.facet(:rating_range)
|
322
|
-
facet.rows[0].value.
|
323
|
-
facet.rows[0].count.
|
324
|
-
facet.rows[1].value.
|
325
|
-
facet.rows[1].count.
|
326
|
-
facet.rows[2].value.
|
327
|
-
facet.rows[2].count.
|
535
|
+
expect(facet.rows[0].value).to eq(3.0..4.0)
|
536
|
+
expect(facet.rows[0].count).to eq(3)
|
537
|
+
expect(facet.rows[1].value).to eq(1.0..2.0)
|
538
|
+
expect(facet.rows[1].count).to eq(2)
|
539
|
+
expect(facet.rows[2].value).to eq(4.0..5.0)
|
540
|
+
expect(facet.rows[2].count).to eq(1)
|
328
541
|
end
|
329
542
|
end
|
330
543
|
end
|