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
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
|