sunspot 2.0.0.pre.120925 → 2.0.0.pre.130115
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/lib/sunspot/dsl/field_query.rb +0 -2
- data/lib/sunspot/dsl/fulltext.rb +0 -2
- data/lib/sunspot/field.rb +3 -2
- data/lib/sunspot/query/common_query.rb +3 -0
- data/lib/sunspot/query/dismax.rb +6 -0
- data/lib/sunspot/query/filter.rb +1 -1
- data/lib/sunspot/query/function_query.rb +8 -3
- data/lib/sunspot/query/geo.rb +1 -1
- data/lib/sunspot/query/range_facet.rb +35 -1
- data/lib/sunspot/query/sort.rb +11 -1
- data/lib/sunspot/search/paginated_collection.rb +3 -9
- data/lib/sunspot/setup.rb +1 -0
- data/lib/sunspot/type.rb +1 -1
- data/lib/sunspot/util.rb +1 -1
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/query/faceting_examples.rb +11 -0
- data/spec/api/query/function_spec.rb +27 -0
- data/spec/api/query/ordering_pagination_examples.rb +21 -0
- data/spec/api/search/paginated_collection_spec.rb +12 -0
- data/spec/integration/scoped_search_spec.rb +37 -1
- metadata +41 -21
@@ -70,8 +70,6 @@ module Sunspot
|
|
70
70
|
#
|
71
71
|
# field_name<Symbol>:: the field to use for grouping
|
72
72
|
def group(*field_names, &block)
|
73
|
-
options = Sunspot::Util.extract_options_from(field_names)
|
74
|
-
|
75
73
|
field_names.each do |field_name|
|
76
74
|
field = @setup.field(field_name)
|
77
75
|
group = @query.add_group(Sunspot::Query::FieldGroup.new(field))
|
data/lib/sunspot/dsl/fulltext.rb
CHANGED
data/lib/sunspot/field.rb
CHANGED
@@ -12,6 +12,7 @@ module Sunspot
|
|
12
12
|
@name, @type = name.to_sym, type
|
13
13
|
@stored = !!options.delete(:stored)
|
14
14
|
@more_like_this = !!options.delete(:more_like_this)
|
15
|
+
@multiple ||= false
|
15
16
|
set_indexed_name(options)
|
16
17
|
raise ArgumentError, "Field of type #{type} cannot be used for more_like_this" unless type.accepts_more_like_this? or !@more_like_this
|
17
18
|
end
|
@@ -34,7 +35,7 @@ module Sunspot
|
|
34
35
|
#
|
35
36
|
def to_indexed(value)
|
36
37
|
if value.is_a? Array
|
37
|
-
if
|
38
|
+
if multiple?
|
38
39
|
value.map { |val| to_indexed(val) }
|
39
40
|
else
|
40
41
|
raise ArgumentError, "#{name} is not a multiple-value field, so it cannot index values #{value.inspect}"
|
@@ -106,7 +107,7 @@ module Sunspot
|
|
106
107
|
if options[:as]
|
107
108
|
options.delete(:as).to_s
|
108
109
|
else
|
109
|
-
"#{@type.indexed_name(@name).to_s}#{'m' if
|
110
|
+
"#{@type.indexed_name(@name).to_s}#{'m' if multiple? }#{'s' if @stored}#{'v' if more_like_this?}"
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
data/lib/sunspot/query/dismax.rb
CHANGED
data/lib/sunspot/query/filter.rb
CHANGED
@@ -5,6 +5,11 @@ module Sunspot
|
|
5
5
|
#
|
6
6
|
class FunctionQuery
|
7
7
|
include RSolr::Char
|
8
|
+
|
9
|
+
def ^(y)
|
10
|
+
@boost_amount = y
|
11
|
+
self
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
15
|
#
|
@@ -16,7 +21,7 @@ module Sunspot
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def to_s
|
19
|
-
Type.to_literal(@constant)
|
24
|
+
Type.to_literal(@constant) << (@boost_amount ? "^#{@boost_amount}" : "")
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
@@ -29,7 +34,7 @@ module Sunspot
|
|
29
34
|
end
|
30
35
|
|
31
36
|
def to_s
|
32
|
-
"#{escape(@field.indexed_name)}"
|
37
|
+
"#{escape(@field.indexed_name)}" << (@boost_amount ? "^#{@boost_amount}" : "")
|
33
38
|
end
|
34
39
|
end
|
35
40
|
|
@@ -45,7 +50,7 @@ module Sunspot
|
|
45
50
|
|
46
51
|
def to_s
|
47
52
|
params = @function_args.map { |arg| arg.to_s }.join(",")
|
48
|
-
"#{@function_name}(#{params})"
|
53
|
+
"#{@function_name}(#{params})" << (@boost_amount ? "^#{@boost_amount}" : "")
|
49
54
|
end
|
50
55
|
end
|
51
56
|
end
|
data/lib/sunspot/query/geo.rb
CHANGED
@@ -1,15 +1,49 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Query
|
3
|
+
|
3
4
|
class RangeFacet < AbstractFieldFacet
|
5
|
+
def initialize(field, options)
|
6
|
+
if exclude_filters = options[:exclude]
|
7
|
+
@exclude_tag = Util.Array(exclude_filters).map do |filter|
|
8
|
+
filter.tag
|
9
|
+
end.join(',')
|
10
|
+
end
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
4
14
|
def to_params
|
5
15
|
params = super
|
6
|
-
params[:"facet.range"] = [
|
16
|
+
params[:"facet.range"] = [field_name_with_local_params]
|
7
17
|
params[qualified_param('range.start')] = @field.to_indexed(@options[:range].first)
|
8
18
|
params[qualified_param('range.end')] = @field.to_indexed(@options[:range].last)
|
9
19
|
params[qualified_param('range.gap')] = "#{@options[:range_interval] || 10}"
|
10
20
|
params[qualified_param('range.include')] = @options[:include].to_s if @options[:include]
|
11
21
|
params
|
12
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def local_params
|
27
|
+
@local_params ||=
|
28
|
+
begin
|
29
|
+
local_params = {}
|
30
|
+
local_params[:ex] = @exclude_tag if @exclude_tag
|
31
|
+
local_params[:key] = @options[:name] if @options[:name]
|
32
|
+
local_params
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def field_name_with_local_params
|
37
|
+
if local_params.empty?
|
38
|
+
@field.indexed_name
|
39
|
+
else
|
40
|
+
pairs = local_params.map do |key, value|
|
41
|
+
"#{key}=#{value}"
|
42
|
+
end
|
43
|
+
"{!#{pairs.join(' ')}}#{@field.indexed_name}"
|
44
|
+
end
|
45
|
+
end
|
13
46
|
end
|
47
|
+
|
14
48
|
end
|
15
49
|
end
|
data/lib/sunspot/query/sort.rb
CHANGED
@@ -76,8 +76,18 @@ module Sunspot
|
|
76
76
|
# (usually) randomly.
|
77
77
|
#
|
78
78
|
class RandomSort < Abstract
|
79
|
+
def initialize(options_or_direction=nil)
|
80
|
+
if options_or_direction.is_a?(Hash)
|
81
|
+
@seed, @direction = options_or_direction[:seed], options_or_direction[:direction]
|
82
|
+
else
|
83
|
+
@direction = options_or_direction
|
84
|
+
end
|
85
|
+
|
86
|
+
@direction = (@direction || :asc).to_sym
|
87
|
+
end
|
88
|
+
|
79
89
|
def to_param
|
80
|
-
"random_#{rand(1<<
|
90
|
+
"random_#{@seed || rand(1<<6)} #{direction_for_solr}"
|
81
91
|
end
|
82
92
|
end
|
83
93
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Search
|
3
3
|
|
4
|
-
class PaginatedCollection
|
5
|
-
instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval|object_id/ }
|
4
|
+
class PaginatedCollection < Array
|
6
5
|
|
7
6
|
attr_reader :current_page, :per_page
|
8
7
|
attr_accessor :total_count
|
@@ -11,10 +10,10 @@ module Sunspot
|
|
11
10
|
alias :limit_value :per_page
|
12
11
|
|
13
12
|
def initialize(collection, page, per_page, total)
|
14
|
-
@collection = collection
|
15
13
|
@current_page = page
|
16
14
|
@per_page = per_page
|
17
15
|
@total_count = total
|
16
|
+
replace collection
|
18
17
|
end
|
19
18
|
|
20
19
|
def total_pages
|
@@ -45,12 +44,7 @@ module Sunspot
|
|
45
44
|
def offset
|
46
45
|
(current_page - 1) * per_page
|
47
46
|
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def method_missing(method, *args, &block)
|
52
|
-
@collection.send(method, *args, &block)
|
53
|
-
end
|
47
|
+
alias :offset_value :offset
|
54
48
|
|
55
49
|
end
|
56
50
|
end
|
data/lib/sunspot/setup.rb
CHANGED
@@ -14,6 +14,7 @@ module Sunspot
|
|
14
14
|
@stored_field_factories_cache = Hash.new { |h, k| h[k] = [] }
|
15
15
|
@more_like_this_field_factories_cache = Hash.new { |h, k| h[k] = [] }
|
16
16
|
@dsl = DSL::Fields.new(self)
|
17
|
+
@document_boost_extractor = nil
|
17
18
|
add_field_factory(:class, Type::ClassType.instance)
|
18
19
|
end
|
19
20
|
|
data/lib/sunspot/type.rb
CHANGED
data/lib/sunspot/util.rb
CHANGED
@@ -202,7 +202,7 @@ module Sunspot
|
|
202
202
|
class <<self
|
203
203
|
def instance_eval_with_context(receiver, &block)
|
204
204
|
calling_context = eval('self', block.binding)
|
205
|
-
if parent_calling_context = calling_context.instance_eval{@__calling_context__}
|
205
|
+
if parent_calling_context = calling_context.instance_eval{@__calling_context__ if defined?(@__calling_context__)}
|
206
206
|
calling_context = parent_calling_context
|
207
207
|
end
|
208
208
|
new(receiver, calling_context).instance_eval(&block)
|
data/lib/sunspot/version.rb
CHANGED
@@ -287,6 +287,17 @@ shared_examples_for "facetable query" do
|
|
287
287
|
connection.should have_last_search_with(:"f.average_rating_ft.facet.range.gap" => "1")
|
288
288
|
end
|
289
289
|
|
290
|
+
it 'tags and excludes a scope filter in a range facet' do
|
291
|
+
search do |query|
|
292
|
+
blog_filter = query.with(:blog_id, 1)
|
293
|
+
query.facet(:average_rating, :range => @range, :exclude => blog_filter)
|
294
|
+
end
|
295
|
+
filter_tag = get_filter_tag('blog_id_i:1')
|
296
|
+
connection.should have_last_search_with(
|
297
|
+
:"facet.range" => %W({!ex=#{filter_tag}}average_rating_ft)
|
298
|
+
)
|
299
|
+
end
|
300
|
+
|
290
301
|
it 'sets the include if one is specified' do
|
291
302
|
search do |query|
|
292
303
|
query.facet :average_rating, :range => @range, :include => :edge
|
@@ -10,6 +10,15 @@ describe 'function query' do
|
|
10
10
|
connection.should have_last_search_including(:bf, 'average_rating_ft')
|
11
11
|
end
|
12
12
|
|
13
|
+
it "should send query to solr with boost function and boost amount" do
|
14
|
+
session.search Post do
|
15
|
+
keywords('pizza') do
|
16
|
+
boost(function { :average_rating }^5)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
connection.should have_last_search_including(:bf, 'average_rating_ft^5')
|
20
|
+
end
|
21
|
+
|
13
22
|
it "should handle boost function with constant float" do
|
14
23
|
session.search Post do
|
15
24
|
keywords('pizza') do
|
@@ -19,6 +28,15 @@ describe 'function query' do
|
|
19
28
|
connection.should have_last_search_including(:bf, '10.5')
|
20
29
|
end
|
21
30
|
|
31
|
+
it "should handle boost function with constant float and boost amount" do
|
32
|
+
session.search Post do
|
33
|
+
keywords('pizza') do
|
34
|
+
boost(function { 10.5 }^5)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
connection.should have_last_search_including(:bf, '10.5^5')
|
38
|
+
end
|
39
|
+
|
22
40
|
it "should handle boost function with time literal" do
|
23
41
|
session.search Post do
|
24
42
|
keywords('pizza') do
|
@@ -45,6 +63,15 @@ describe 'function query' do
|
|
45
63
|
end
|
46
64
|
connection.should have_last_search_including(:bf, 'sub(average_rating_ft,10)')
|
47
65
|
end
|
66
|
+
|
67
|
+
it "should handle boost amounts on function query block" do
|
68
|
+
session.search Post do
|
69
|
+
keywords('pizza') do
|
70
|
+
boost(function { sub(:average_rating, 10)^5 })
|
71
|
+
end
|
72
|
+
end
|
73
|
+
connection.should have_last_search_including(:bf, 'sub(average_rating_ft,10)^5')
|
74
|
+
end
|
48
75
|
|
49
76
|
it "should handle nested functions in a function query block" do
|
50
77
|
session.search Post do
|
@@ -68,6 +68,27 @@ shared_examples_for 'sortable query' do
|
|
68
68
|
connection.searches.last[:sort].should =~ /^random_\d+ asc$/
|
69
69
|
end
|
70
70
|
|
71
|
+
it 'orders by random with declared direction' do
|
72
|
+
search do
|
73
|
+
order_by :random, :desc
|
74
|
+
end
|
75
|
+
connection.searches.last[:sort].should =~ /^random_\d+ desc$/
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'orders by random with provided seed value' do
|
79
|
+
search do
|
80
|
+
order_by :random, :seed => 9001
|
81
|
+
end
|
82
|
+
connection.searches.last[:sort].should =~ /^random_9001 asc$/
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'orders by random with provided seed value and direction' do
|
86
|
+
search do
|
87
|
+
order_by :random, :seed => 12345, :direction => :desc
|
88
|
+
end
|
89
|
+
connection.searches.last[:sort].should =~ /^random_12345 desc$/
|
90
|
+
end
|
91
|
+
|
71
92
|
it 'orders by score' do
|
72
93
|
search do
|
73
94
|
order_by :score, :desc
|
@@ -5,6 +5,18 @@ describe "PaginatedCollection" do
|
|
5
5
|
|
6
6
|
it { subject.should be_an(Array) }
|
7
7
|
|
8
|
+
describe "#send" do
|
9
|
+
it 'should allow send' do
|
10
|
+
expect { subject.send(:current_page) }.not_to raise_error(NoMethodError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#respond_to?" do
|
15
|
+
it 'should return true for current_page' do
|
16
|
+
subject.respond_to?(:current_page).should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
8
20
|
context "behaves like a WillPaginate::Collection" do
|
9
21
|
it { subject.total_entries.should eql(20) }
|
10
22
|
it { subject.total_pages.should eql(2) }
|
@@ -372,9 +372,12 @@ describe 'scoped_search' do
|
|
372
372
|
end
|
373
373
|
|
374
374
|
describe 'ordering by random' do
|
375
|
-
|
375
|
+
before do
|
376
376
|
Sunspot.remove_all
|
377
377
|
Sunspot.index!(Array.new(100) { Post.new })
|
378
|
+
end
|
379
|
+
|
380
|
+
it 'should order randomly (run this test again if it fails)' do
|
378
381
|
result_sets = Array.new(2) do
|
379
382
|
Sunspot.search(Post) { order_by_random }.results.map do |result|
|
380
383
|
result.id
|
@@ -382,5 +385,38 @@ describe 'scoped_search' do
|
|
382
385
|
end
|
383
386
|
result_sets[0].should_not == result_sets[1]
|
384
387
|
end
|
388
|
+
|
389
|
+
# This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
|
390
|
+
it 'should order randomly using the order_by function and passing a direction' do
|
391
|
+
result_sets = Array.new(2) do
|
392
|
+
Sunspot.search(Post) { order_by(:random, :desc) }.results.map do |result|
|
393
|
+
result.id
|
394
|
+
end
|
395
|
+
end
|
396
|
+
result_sets[0].should_not == result_sets[1]
|
397
|
+
end
|
398
|
+
|
399
|
+
context 'when providing a custom seed value' do
|
400
|
+
before do
|
401
|
+
@first_results = Sunspot.search(Post) do
|
402
|
+
order_by(:random, :seed => 12345)
|
403
|
+
end.results.map { |result| result.id }
|
404
|
+
end
|
405
|
+
|
406
|
+
# This could fail if the random set returned just happens to be the same as the last random set (the nature of randomness)
|
407
|
+
it 'should return different results when passing a different seed value' do
|
408
|
+
next_results = Sunspot.search(Post) do
|
409
|
+
order_by(:random, :seed => 54321)
|
410
|
+
end.results.map { |result| result.id }
|
411
|
+
next_results.should_not == @first_results
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'should return the same results when passing the same seed value' do
|
415
|
+
next_results = Sunspot.search(Post) do
|
416
|
+
order_by(:random, :seed => 12345)
|
417
|
+
end.results.map { |result| result.id }
|
418
|
+
next_results.should == @first_results
|
419
|
+
end
|
420
|
+
end
|
385
421
|
end
|
386
422
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunspot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.pre.
|
4
|
+
version: 2.0.0.pre.130115
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,52 +27,72 @@ authors:
|
|
27
27
|
autorequire:
|
28
28
|
bindir: bin
|
29
29
|
cert_chain: []
|
30
|
-
date:
|
30
|
+
date: 2013-01-15 00:00:00.000000000 Z
|
31
31
|
dependencies:
|
32
32
|
- !ruby/object:Gem::Dependency
|
33
33
|
name: rsolr
|
34
|
-
|
35
|
-
|
34
|
+
prerelease: false
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - ~>
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: 1.0.7
|
40
|
+
none: false
|
40
41
|
type: :runtime
|
41
|
-
|
42
|
-
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.0.7
|
47
|
+
none: false
|
43
48
|
- !ruby/object:Gem::Dependency
|
44
49
|
name: pr_geohash
|
45
|
-
|
46
|
-
|
50
|
+
prerelease: false
|
51
|
+
requirement: !ruby/object:Gem::Requirement
|
47
52
|
requirements:
|
48
53
|
- - ~>
|
49
54
|
- !ruby/object:Gem::Version
|
50
55
|
version: '1.0'
|
56
|
+
none: false
|
51
57
|
type: :runtime
|
52
|
-
|
53
|
-
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.0'
|
63
|
+
none: false
|
54
64
|
- !ruby/object:Gem::Dependency
|
55
65
|
name: rspec
|
56
|
-
|
57
|
-
|
66
|
+
prerelease: false
|
67
|
+
requirement: !ruby/object:Gem::Requirement
|
58
68
|
requirements:
|
59
69
|
- - ~>
|
60
70
|
- !ruby/object:Gem::Version
|
61
71
|
version: 2.6.0
|
72
|
+
none: false
|
62
73
|
type: :development
|
63
|
-
|
64
|
-
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.6.0
|
79
|
+
none: false
|
65
80
|
- !ruby/object:Gem::Dependency
|
66
81
|
name: hanna
|
67
|
-
|
68
|
-
|
82
|
+
prerelease: false
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
69
84
|
requirements:
|
70
85
|
- - ! '>='
|
71
86
|
- !ruby/object:Gem::Version
|
72
87
|
version: '0'
|
88
|
+
none: false
|
73
89
|
type: :development
|
74
|
-
|
75
|
-
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
none: false
|
76
96
|
description: ! " Sunspot is a library providing a powerful, all-ruby API for the
|
77
97
|
Solr search engine. Sunspot manages the configuration of persistent\n Ruby classes
|
78
98
|
for search and indexing and exposes Solr's most powerful features through a collection
|
@@ -276,20 +296,20 @@ rdoc_options:
|
|
276
296
|
require_paths:
|
277
297
|
- lib
|
278
298
|
required_ruby_version: !ruby/object:Gem::Requirement
|
279
|
-
none: false
|
280
299
|
requirements:
|
281
300
|
- - ! '>='
|
282
301
|
- !ruby/object:Gem::Version
|
283
302
|
version: '0'
|
284
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
285
303
|
none: false
|
304
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
286
305
|
requirements:
|
287
306
|
- - ! '>'
|
288
307
|
- !ruby/object:Gem::Version
|
289
308
|
version: 1.3.1
|
309
|
+
none: false
|
290
310
|
requirements: []
|
291
311
|
rubyforge_project: sunspot
|
292
|
-
rubygems_version: 1.8.
|
312
|
+
rubygems_version: 1.8.24
|
293
313
|
signing_key:
|
294
314
|
specification_version: 3
|
295
315
|
summary: Library for expressive, powerful interaction with the Solr search engine
|