sunspot 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -0
- data/TODO +6 -5
- data/bin/sunspot-solr +4 -0
- data/installer/config/schema.yml +24 -0
- data/lib/sunspot/composite_setup.rb +14 -0
- data/lib/sunspot/dsl/adjustable.rb +47 -0
- data/lib/sunspot/dsl/fulltext.rb +23 -8
- data/lib/sunspot/dsl/function.rb +14 -0
- data/lib/sunspot/dsl/functional.rb +41 -0
- data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
- data/lib/sunspot/dsl/paginatable.rb +28 -0
- data/lib/sunspot/dsl/search.rb +1 -1
- data/lib/sunspot/dsl/{query.rb → standard_query.rb} +4 -49
- data/lib/sunspot/dsl.rb +3 -2
- data/lib/sunspot/field.rb +16 -2
- data/lib/sunspot/indexer.rb +1 -1
- data/lib/sunspot/installer/schema_builder.rb +1 -1
- data/lib/sunspot/installer/solrconfig_updater.rb +13 -0
- data/lib/sunspot/installer/task_helper.rb +1 -1
- data/lib/sunspot/query/abstract_field_facet.rb +5 -0
- data/lib/sunspot/query/boost_query.rb +5 -1
- data/lib/sunspot/query/{query.rb → common_query.rb} +26 -20
- data/lib/sunspot/query/composite_fulltext.rb +31 -0
- data/lib/sunspot/query/dismax.rb +45 -6
- data/lib/sunspot/query/function_query.rb +52 -0
- data/lib/sunspot/query/more_like_this.rb +60 -0
- data/lib/sunspot/query/more_like_this_query.rb +12 -0
- data/lib/sunspot/query/standard_query.rb +20 -0
- data/lib/sunspot/query/text_field_boost.rb +2 -0
- data/lib/sunspot/query.rb +3 -2
- data/lib/sunspot/search/abstract_search.rb +302 -0
- data/lib/sunspot/search/date_facet.rb +1 -1
- data/lib/sunspot/search/facet_row.rb +1 -1
- data/lib/sunspot/search/field_facet.rb +1 -1
- data/lib/sunspot/search/highlight.rb +1 -1
- data/lib/sunspot/search/hit.rb +1 -1
- data/lib/sunspot/search/more_like_this_search.rb +31 -0
- data/lib/sunspot/search/query_facet.rb +1 -1
- data/lib/sunspot/search/standard_search.rb +21 -0
- data/lib/sunspot/search.rb +3 -288
- data/lib/sunspot/server.rb +8 -4
- data/lib/sunspot/session.rb +30 -2
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +1 -1
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +9 -0
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +9 -2
- data/lib/sunspot/setup.rb +32 -3
- data/lib/sunspot/type.rb +74 -0
- data/lib/sunspot/util.rb +3 -2
- data/lib/sunspot/version.rb +1 -1
- data/lib/sunspot.rb +9 -1
- data/solr/solr/conf/schema.xml +12 -0
- data/solr/solr/conf/solrconfig.xml +6 -0
- data/spec/api/indexer/attributes_spec.rb +9 -3
- data/spec/api/indexer/fulltext_spec.rb +2 -2
- data/spec/api/indexer/removal_spec.rb +1 -1
- data/spec/api/query/advanced_manipulation_examples.rb +35 -0
- data/spec/api/query/{connectives_spec.rb → connectives_examples.rb} +19 -19
- data/spec/api/query/{dynamic_fields_spec.rb → dynamic_fields_examples.rb} +33 -17
- data/spec/api/query/{faceting_spec.rb → faceting_examples.rb} +146 -43
- data/spec/api/query/{fulltext_spec.rb → fulltext_examples.rb} +81 -47
- data/spec/api/query/function_spec.rb +70 -0
- data/spec/api/query/{highlighting_spec.rb → highlighting_examples.rb} +27 -27
- data/spec/api/query/{local_spec.rb → local_examples.rb} +5 -5
- data/spec/api/query/more_like_this_spec.rb +140 -0
- data/spec/api/query/{ordering_pagination_spec.rb → ordering_pagination_examples.rb} +16 -16
- data/spec/api/query/{scope_spec.rb → scope_examples.rb} +44 -61
- data/spec/api/query/standard_spec.rb +28 -0
- data/spec/api/query/{text_field_scoping_spec.rb → text_field_scoping_examples.rb} +5 -5
- data/spec/api/search/dynamic_fields_spec.rb +6 -0
- data/spec/api/search/faceting_spec.rb +10 -10
- data/spec/api/search/hits_spec.rb +1 -1
- data/spec/api/search/results_spec.rb +10 -0
- data/spec/api/server_spec.rb +6 -0
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +2 -2
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +17 -0
- data/spec/api/spec_helper.rb +2 -0
- data/spec/helpers/query_helper.rb +25 -0
- data/spec/helpers/search_helper.rb +4 -0
- data/spec/integration/faceting_spec.rb +8 -0
- data/spec/integration/keyword_search_spec.rb +75 -3
- data/spec/integration/local_search_spec.rb +1 -1
- data/spec/integration/more_like_this_spec.rb +43 -0
- data/spec/mocks/comment.rb +1 -1
- data/spec/mocks/connection.rb +27 -12
- data/spec/mocks/post.rb +5 -4
- data/spec/spec_helper.rb +4 -21
- data/tasks/gemspec.rake +1 -1
- metadata +39 -27
- data/spec/api/query/adjust_params_spec.rb +0 -37
- data/spec/api/query/facet_local_params_spec.rb +0 -103
data/README.rdoc
CHANGED
@@ -230,6 +230,9 @@ Sunspot repository at `upstream`:
|
|
230
230
|
* Tom Coleman (tom@thesnail.org)
|
231
231
|
* Matt Mitchell (goodieboy@gmail.com)
|
232
232
|
* Nathan Beyer (nbeyer@gmail.com)
|
233
|
+
* Kieran Topping
|
234
|
+
* Nicolas Braem (nicolas.braem@gmail.com)
|
235
|
+
* Jeremy Ashkenas (jashkenas@gmail.com)
|
233
236
|
|
234
237
|
== License
|
235
238
|
|
data/TODO
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
=== Sunspot 1.
|
2
|
-
*
|
1
|
+
=== Sunspot 1.1.x ===
|
2
|
+
* commitWithin (needs support from RSolr, currently available in master)
|
3
|
+
* commit options (non-blocking, etc.)
|
3
4
|
|
4
|
-
===
|
5
|
+
=== Someday ===
|
5
6
|
* Shorthand arguments to Sunspot#search
|
6
7
|
* Rudimentary fulltext prefixing support
|
7
|
-
* commitWithin (need solr-ruby support for this)
|
8
|
-
* Support Solr functions (e.g. dismax :bf)
|
9
8
|
|
10
9
|
=== Solr 1.5 ===
|
11
10
|
* Field Collapsing (SOLR-236)
|
12
11
|
* Support for official spatial support (SOLR-773)
|
12
|
+
* Support sorting by function
|
13
|
+
* Support string constants in functions
|
data/bin/sunspot-solr
CHANGED
@@ -30,6 +30,10 @@ OptionParser.new do |opts|
|
|
30
30
|
server.solr_home = File.expand_path(s)
|
31
31
|
end
|
32
32
|
|
33
|
+
opts.on '-j', '--solr-jar=JAR', 'Solr start jar' do |j|
|
34
|
+
server.solr_jar = File.expand_path(j)
|
35
|
+
end
|
36
|
+
|
33
37
|
opts.on '--pid-dir=PID_DIR', 'Directory for pid files' do |pd|
|
34
38
|
server.pid_dir = File.expand_path(pd)
|
35
39
|
end
|
data/installer/config/schema.yml
CHANGED
@@ -12,37 +12,60 @@ types: !omap
|
|
12
12
|
- boolean:
|
13
13
|
class: BoolField
|
14
14
|
suffix: b
|
15
|
+
invariants:
|
16
|
+
termVectors: valse
|
15
17
|
- date:
|
16
18
|
class: DateField
|
17
19
|
suffix: d
|
20
|
+
invariants:
|
21
|
+
termVectors: valse
|
18
22
|
- rand:
|
19
23
|
class: RandomSortField
|
20
24
|
- sdouble:
|
21
25
|
class: SortableDoubleField
|
22
26
|
suffix: e
|
27
|
+
invariants:
|
28
|
+
termVectors: valse
|
23
29
|
- sfloat:
|
24
30
|
class: SortableFloatField
|
25
31
|
suffix: f
|
32
|
+
invariants:
|
33
|
+
termVectors: valse
|
26
34
|
- sint:
|
27
35
|
class: SortableIntField
|
28
36
|
suffix: i
|
37
|
+
invariants:
|
38
|
+
termVectors: valse
|
29
39
|
- slong:
|
30
40
|
class: SortableLongField
|
31
41
|
suffix: l
|
42
|
+
invariants:
|
43
|
+
termVectors: valse
|
32
44
|
- string:
|
33
45
|
class: StrField
|
34
46
|
suffix: s
|
47
|
+
invariants:
|
48
|
+
termVectors: valse
|
35
49
|
- tint:
|
36
50
|
class: TrieIntField
|
37
51
|
suffix: it
|
52
|
+
invariants:
|
53
|
+
termVectors: valse
|
38
54
|
- tfloat:
|
39
55
|
class: TrieFloatField
|
40
56
|
suffix: ft
|
57
|
+
invariants:
|
58
|
+
termVectors: valse
|
41
59
|
- tdouble:
|
42
60
|
class: TrieDoubleField
|
61
|
+
suffix: et
|
62
|
+
invariants:
|
63
|
+
termVectors: valse
|
43
64
|
- tdate:
|
44
65
|
class: TrieDateField
|
45
66
|
suffix: dt
|
67
|
+
invariants:
|
68
|
+
termVectors: valse
|
46
69
|
fixed: !omap
|
47
70
|
- id:
|
48
71
|
type: string
|
@@ -69,3 +92,4 @@ fixed: !omap
|
|
69
92
|
variants: !omap
|
70
93
|
- multiValued: m
|
71
94
|
- stored: s
|
95
|
+
- termVectors: v
|
@@ -112,6 +112,10 @@ module Sunspot
|
|
112
112
|
@text_fields ||= text_fields_hash.values.map { |set| set.to_a }.flatten
|
113
113
|
end
|
114
114
|
|
115
|
+
def all_more_like_this_fields
|
116
|
+
@more_like_this_fields ||= more_like_this_fields_hash.values.map { |set| set.to_a }.flatten
|
117
|
+
end
|
118
|
+
|
115
119
|
private
|
116
120
|
|
117
121
|
#
|
@@ -132,6 +136,16 @@ module Sunspot
|
|
132
136
|
end
|
133
137
|
end
|
134
138
|
|
139
|
+
def more_like_this_fields_hash
|
140
|
+
@more_like_this_fields_hash ||=
|
141
|
+
setups.inject({}) do |hash, setup|
|
142
|
+
setup.all_more_like_this_fields.each do |more_like_this_field|
|
143
|
+
(hash[more_like_this_field.name] ||= Set.new) << more_like_this_field
|
144
|
+
end
|
145
|
+
hash
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
135
149
|
#
|
136
150
|
# Return a hash of field names to field objects, containing all fields
|
137
151
|
# that are common to all of the classes enclosed. In order for fields
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL #:nodoc:
|
3
|
+
module Adjustable #:nodoc
|
4
|
+
# <strong>Expert:</strong> Adjust or reset the parameters passed to Solr.
|
5
|
+
# The adjustment will take place just before sending the params to solr,
|
6
|
+
# after Sunspot builds the Solr params based on the methods called in the
|
7
|
+
# DSL.
|
8
|
+
#
|
9
|
+
# Under normal circumstances, using this method should not be necessary;
|
10
|
+
# if you find that it is, please consider submitting a feature request.
|
11
|
+
# Using this method requires knowledge of Sunspot's internal Solr schema
|
12
|
+
# and Solr query representations, which are not part of Sunspot's public
|
13
|
+
# API; they could change at any time. <strong>This method is unsupported
|
14
|
+
# and your mileage may vary.</strong>
|
15
|
+
#
|
16
|
+
# ==== Examples
|
17
|
+
#
|
18
|
+
# Sunspot.search(Post) do
|
19
|
+
# adjust_solr_params do |params|
|
20
|
+
# params[:q] += ' AND something_s:more'
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# Sunspot.more_like_this(my_post) do
|
25
|
+
# adjust_solr_params do |params|
|
26
|
+
# params["mlt.match.include"] = true
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
def adjust_solr_params( &block )
|
31
|
+
@query.solr_parameter_adjustment = block
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# <strong>Expert:</strong> Use a custom request handler for this search.
|
36
|
+
# The general use case for this would be a request handler configuration
|
37
|
+
# you've defined in solrconfig that has different search components,
|
38
|
+
# defaults, etc. Using this to point at an entirely different type of
|
39
|
+
# request handler that Sunspot doesn't support probably won't get you very
|
40
|
+
# far.
|
41
|
+
#
|
42
|
+
def request_handler(request_handler)
|
43
|
+
@search.request_handler = request_handler
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/sunspot/dsl/fulltext.rb
CHANGED
@@ -7,6 +7,9 @@ module Sunspot
|
|
7
7
|
class Fulltext
|
8
8
|
attr_reader :exclude_fields #:nodoc:
|
9
9
|
|
10
|
+
# accept function in boost
|
11
|
+
include Functional
|
12
|
+
|
10
13
|
def initialize(query, setup) #:nodoc:
|
11
14
|
@query, @setup = query, setup
|
12
15
|
@fields_added = false
|
@@ -139,10 +142,15 @@ module Sunspot
|
|
139
142
|
|
140
143
|
#
|
141
144
|
# Boost queries allow specification of an arbitrary scope for which
|
142
|
-
# matching documents should receive an extra boost.
|
145
|
+
# matching documents should receive an extra boost. You can either specify
|
146
|
+
# a boost factor and a block, or a boost function. The block is evaluated
|
143
147
|
# in the usual scope DSL, and field names are attribute fields, not text
|
144
148
|
# fields, as in other scope.
|
145
149
|
#
|
150
|
+
# The boost function can be a constant (numeric or string literal),
|
151
|
+
# a field name or another function. You can build arbitrarily complex
|
152
|
+
# functions, which are passed transparently to solr.
|
153
|
+
#
|
146
154
|
# This method can be called more than once for different boost queries
|
147
155
|
# with different boosts.
|
148
156
|
#
|
@@ -153,16 +161,23 @@ module Sunspot
|
|
153
161
|
# boost(2.0) do
|
154
162
|
# with(:featured, true)
|
155
163
|
# end
|
164
|
+
#
|
165
|
+
# boost(function { sum(:average_rating, product(:popularity, 10)) })
|
156
166
|
# end
|
157
167
|
# end
|
158
168
|
#
|
159
|
-
# In the above search, featured posts will receive a boost of 2.0
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
169
|
+
# In the above search, featured posts will receive a boost of 2.0 and all posts
|
170
|
+
# will be boosted by (average_rating + popularity * 10).
|
171
|
+
#
|
172
|
+
def boost(factor_or_function, &block)
|
173
|
+
if factor_or_function.is_a?(Sunspot::Query::FunctionQuery)
|
174
|
+
@query.add_boost_function(factor_or_function)
|
175
|
+
else
|
176
|
+
Sunspot::Util.instance_eval_or_call(
|
177
|
+
Scope.new(@query.create_boost_query(factor_or_function), @setup),
|
178
|
+
&block
|
179
|
+
)
|
180
|
+
end
|
166
181
|
end
|
167
182
|
|
168
183
|
#
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL
|
3
|
+
class Function #:nodoc:
|
4
|
+
def initialize(functional) #:nodoc:
|
5
|
+
@functional = functional
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(method, *args, &block)
|
9
|
+
function_args = args.map { |arg| @functional.create_function_query(arg) }
|
10
|
+
Sunspot::Query::FunctionalFunctionQuery.new(method, function_args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL
|
3
|
+
#
|
4
|
+
# Mixin DSL to accept functions.
|
5
|
+
#
|
6
|
+
module Functional
|
7
|
+
|
8
|
+
#
|
9
|
+
# Specify a function query with a block that returns an expression.
|
10
|
+
#
|
11
|
+
# === Examples
|
12
|
+
#
|
13
|
+
# function { 10 }
|
14
|
+
# function { :average_rating }
|
15
|
+
# function { sum(:average_rating, 10) }
|
16
|
+
#
|
17
|
+
def function(&block)
|
18
|
+
expression = Sunspot::Util.instance_eval_or_call(
|
19
|
+
Function.new(self),
|
20
|
+
&block
|
21
|
+
)
|
22
|
+
create_function_query(expression)
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Creates an AbstractFunctionQuery from an expression, also called by
|
27
|
+
# Sunspot::DSL::Function
|
28
|
+
#
|
29
|
+
def create_function_query(expression) #:nodoc:
|
30
|
+
if expression.is_a?(Sunspot::Query::FunctionQuery)
|
31
|
+
expression
|
32
|
+
elsif expression.is_a?(Symbol)
|
33
|
+
Sunspot::Query::FieldFunctionQuery.new(@setup.field(expression))
|
34
|
+
else
|
35
|
+
Sunspot::Query::ConstantFunctionQuery.new(expression)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL #:nodoc:
|
3
|
+
#
|
4
|
+
# This class provides the DSL for MoreLikeThis queries.
|
5
|
+
#
|
6
|
+
class MoreLikeThisQuery < FieldQuery
|
7
|
+
include Paginatable, Adjustable
|
8
|
+
|
9
|
+
def fields(*field_names)
|
10
|
+
boosted_fields = field_names.pop if field_names.last.is_a?(Hash)
|
11
|
+
field_names.each do |name|
|
12
|
+
mlt_fields = @setup.more_like_this_fields(name)
|
13
|
+
raise(ArgumentError, "Field #{name} is not setup for more_like_this") if mlt_fields.empty?
|
14
|
+
mlt_fields.each { |field| @query.more_like_this.add_field(field) }
|
15
|
+
end
|
16
|
+
if boosted_fields
|
17
|
+
boosted_fields.each_pair do |field_name, boost|
|
18
|
+
@setup.more_like_this_fields(field_name).each do |field|
|
19
|
+
@query.more_like_this.add_field(field, boost)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def minimum_term_frequency(value)
|
26
|
+
@query.more_like_this.minimum_term_frequency = value
|
27
|
+
end
|
28
|
+
alias_method :mintf, :minimum_term_frequency
|
29
|
+
|
30
|
+
def minimum_document_frequency(value)
|
31
|
+
@query.more_like_this.minimum_document_frequency = value
|
32
|
+
end
|
33
|
+
alias_method :mindf, :minimum_document_frequency
|
34
|
+
|
35
|
+
def minimum_word_length(value)
|
36
|
+
@query.more_like_this.minimum_word_length = value
|
37
|
+
end
|
38
|
+
alias_method :minwl, :minimum_word_length
|
39
|
+
|
40
|
+
def maximum_word_length(value)
|
41
|
+
@query.more_like_this.maximum_word_length = value
|
42
|
+
end
|
43
|
+
alias_method :maxwl, :maximum_word_length
|
44
|
+
|
45
|
+
def maximum_query_terms(value)
|
46
|
+
@query.more_like_this.maximum_query_terms = value
|
47
|
+
end
|
48
|
+
alias_method :maxqt, :maximum_query_terms
|
49
|
+
|
50
|
+
def boost_by_relevance(should_boost)
|
51
|
+
@query.more_like_this.boost_by_relevance = should_boost
|
52
|
+
end
|
53
|
+
alias_method :boost, :boost_by_relevance
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL #:nodoc
|
3
|
+
module Paginatable
|
4
|
+
# Paginate your search. This works the same way as WillPaginate's
|
5
|
+
# paginate().
|
6
|
+
#
|
7
|
+
# Note that Solr searches are _always_ paginated. Not calling #paginate is
|
8
|
+
# the equivalent of calling:
|
9
|
+
#
|
10
|
+
# paginate(:page => 1, :per_page => Sunspot.config.pagination.default_per_page)
|
11
|
+
#
|
12
|
+
# ==== Options (options)
|
13
|
+
#
|
14
|
+
# :page<Integer,String>:: The requested page. The default is 1.
|
15
|
+
#
|
16
|
+
# :per_page<Integer,String>::
|
17
|
+
# How many results to return per page. The default is the value in
|
18
|
+
# +Sunspot.config.pagination.default_per_page+
|
19
|
+
#
|
20
|
+
def paginate(options = {})
|
21
|
+
page = options.delete(:page)
|
22
|
+
per_page = options.delete(:per_page)
|
23
|
+
raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
|
24
|
+
@query.paginate(page, per_page)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/sunspot/dsl/search.rb
CHANGED
@@ -5,7 +5,7 @@ module Sunspot
|
|
5
5
|
# Sunspot.query. See Sunspot::DSL::Query, Sunspot::DSL::FieldQuery, and
|
6
6
|
# Sunspot::DSL::Scope for the full API presented.
|
7
7
|
#
|
8
|
-
class Search <
|
8
|
+
class Search < StandardQuery
|
9
9
|
def initialize(search, setup) #:nodoc:
|
10
10
|
@search = search
|
11
11
|
super(search, search.query, setup)
|
@@ -8,7 +8,9 @@ module Sunspot
|
|
8
8
|
#
|
9
9
|
# See Sunspot.search for usage examples
|
10
10
|
#
|
11
|
-
class
|
11
|
+
class StandardQuery < FieldQuery
|
12
|
+
include Paginatable, Adjustable
|
13
|
+
|
12
14
|
# Specify a phrase that should be searched as fulltext. Only +text+
|
13
15
|
# fields are searched - see DSL::Fields.text
|
14
16
|
#
|
@@ -53,7 +55,7 @@ module Sunspot
|
|
53
55
|
#
|
54
56
|
def fulltext(keywords, options = {}, &block)
|
55
57
|
if keywords && !(keywords.to_s =~ /^\s*$/)
|
56
|
-
fulltext_query = @query.
|
58
|
+
fulltext_query = @query.add_fulltext(keywords)
|
57
59
|
if field_names = options.delete(:fields)
|
58
60
|
Util.Array(field_names).each do |field_name|
|
59
61
|
@setup.text_fields(field_name).each do |field|
|
@@ -101,54 +103,7 @@ module Sunspot
|
|
101
103
|
end
|
102
104
|
alias_method :keywords, :fulltext
|
103
105
|
|
104
|
-
# Paginate your search. This works the same way as WillPaginate's
|
105
|
-
# paginate().
|
106
|
-
#
|
107
|
-
# Note that Solr searches are _always_ paginated. Not calling #paginate is
|
108
|
-
# the equivalent of calling:
|
109
|
-
#
|
110
|
-
# paginate(:page => 1, :per_page => Sunspot.config.pagination.default_per_page)
|
111
|
-
#
|
112
|
-
# ==== Options (options)
|
113
106
|
#
|
114
|
-
# :page<Integer,String>:: The requested page. The default is 1.
|
115
|
-
#
|
116
|
-
# :per_page<Integer,String>::
|
117
|
-
# How many results to return per page. The default is the value in
|
118
|
-
# +Sunspot.config.pagination.default_per_page+
|
119
|
-
#
|
120
|
-
def paginate(options = {})
|
121
|
-
page = options.delete(:page)
|
122
|
-
per_page = options.delete(:per_page)
|
123
|
-
raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
|
124
|
-
@query.paginate(page, per_page)
|
125
|
-
end
|
126
|
-
|
127
|
-
# <strong>Expert:</strong> Adjust or reset the parameters passed to Solr.
|
128
|
-
# The adjustment will take place just before sending the params to solr,
|
129
|
-
# after Sunspot builds the Solr params based on the methods called in the
|
130
|
-
# DSL.
|
131
|
-
#
|
132
|
-
# Under normal circumstances, using this method should not be necessary;
|
133
|
-
# if you find that it is, please consider submitting a feature request.
|
134
|
-
# Using this method requires knowledge of Sunspot's internal Solr schema
|
135
|
-
# and Solr query representations, which are not part of Sunspot's public
|
136
|
-
# API; they could change at any time. <strong>This method is unsupported
|
137
|
-
# and your mileage may vary.</strong>
|
138
|
-
#
|
139
|
-
# ==== Example
|
140
|
-
#
|
141
|
-
# Sunspot.search(Post) do
|
142
|
-
# adjust_solr_params do |params|
|
143
|
-
# params[:q] += ' AND something_s:more'
|
144
|
-
# end
|
145
|
-
# end
|
146
|
-
#
|
147
|
-
def adjust_solr_params( &block )
|
148
|
-
@query.set_solr_parameter_adjustment( block )
|
149
|
-
end
|
150
|
-
|
151
|
-
#
|
152
107
|
# Scope the search by geographical distance from a given point.
|
153
108
|
# +coordinates+ should either respond to #first and #last (e.g. a
|
154
109
|
# two-element array), or to #lat and one of #lng, #lon, or #long.
|
data/lib/sunspot/dsl.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
%w(fields scope field_query
|
2
|
-
search
|
1
|
+
%w(fields scope paginatable adjustable field_query standard_query query_facet
|
2
|
+
functional fulltext restriction search more_like_this_query
|
3
|
+
function).each do |file|
|
3
4
|
require File.join(File.dirname(__FILE__), 'dsl', file)
|
4
5
|
end
|
data/lib/sunspot/field.rb
CHANGED
@@ -10,6 +10,8 @@ module Sunspot
|
|
10
10
|
def initialize(name, type, options = {}) #:nodoc
|
11
11
|
@name, @type = name.to_sym, type
|
12
12
|
@stored = !!options.delete(:stored)
|
13
|
+
@more_like_this = !!options.delete(:more_like_this)
|
14
|
+
raise ArgumentError, "Field of type #{type} cannot be used for more_like_this" unless type.accepts_more_like_this? or !@more_like_this
|
13
15
|
end
|
14
16
|
|
15
17
|
# Convert a value to its representation for Solr indexing. This delegates
|
@@ -77,6 +79,18 @@ module Sunspot
|
|
77
79
|
!!@multiple
|
78
80
|
end
|
79
81
|
|
82
|
+
#
|
83
|
+
# Whether this field can be used for more_like_this queries.
|
84
|
+
# If true, the field is configured to store termVectors.
|
85
|
+
#
|
86
|
+
# ==== Returns
|
87
|
+
#
|
88
|
+
# Boolean:: True if this field can be used for more_like_this queries.
|
89
|
+
#
|
90
|
+
def more_like_this?
|
91
|
+
!!@more_like_this
|
92
|
+
end
|
93
|
+
|
80
94
|
def hash
|
81
95
|
indexed_name.hash
|
82
96
|
end
|
@@ -107,7 +121,7 @@ module Sunspot
|
|
107
121
|
end
|
108
122
|
|
109
123
|
def indexed_name
|
110
|
-
"#{super}#{'s' if @stored}"
|
124
|
+
"#{super}#{'s' if @stored}#{'v' if more_like_this?}"
|
111
125
|
end
|
112
126
|
end
|
113
127
|
|
@@ -140,7 +154,7 @@ module Sunspot
|
|
140
154
|
# String:: The field's indexed name
|
141
155
|
#
|
142
156
|
def indexed_name
|
143
|
-
"#{super}#{'m' if @multiple}#{'s' if @stored}"
|
157
|
+
"#{super}#{'m' if @multiple}#{'s' if @stored}#{'v' if more_like_this?}"
|
144
158
|
end
|
145
159
|
end
|
146
160
|
|
data/lib/sunspot/indexer.rb
CHANGED
@@ -157,7 +157,7 @@ module Sunspot
|
|
157
157
|
|
158
158
|
def add_comment(node)
|
159
159
|
comment_message = " *** This #{node.name} is used by Sunspot! *** "
|
160
|
-
unless (comment = previous_non_text_sibling(node)) && comment.
|
160
|
+
unless (comment = previous_non_text_sibling(node)) && comment.comment? && comment.content =~ /Sunspot/
|
161
161
|
node.add_previous_sibling(Nokogiri::XML::Comment.new(@document, comment_message))
|
162
162
|
end
|
163
163
|
end
|
@@ -46,6 +46,7 @@ module Sunspot
|
|
46
46
|
@root = @document.root
|
47
47
|
maybe_create_spatial_component
|
48
48
|
maybe_add_spatial_component_to_standard_handler
|
49
|
+
maybe_add_more_like_this_handler
|
49
50
|
original_path = "#{@solrconfig_path}.orig"
|
50
51
|
FileUtils.cp(@solrconfig_path, original_path)
|
51
52
|
say("Saved backup of original to #{original_path}")
|
@@ -88,6 +89,18 @@ module Sunspot
|
|
88
89
|
add_element(last_components_node, 'str').content = 'spatial'
|
89
90
|
end
|
90
91
|
end
|
92
|
+
|
93
|
+
def maybe_add_more_like_this_handler
|
94
|
+
unless @root.xpath('requestHandler[@name="/mlt"]').first
|
95
|
+
mlt_node = add_element(
|
96
|
+
@root, 'requestHandler',
|
97
|
+
:name => '/mlt', :class => 'solr.MoreLikeThisHandler'
|
98
|
+
)
|
99
|
+
defaults_node = add_element(mlt_node, 'lst', :name => 'defaults')
|
100
|
+
add_element(defaults_node, 'str', :name => 'mlt.mintf').content = '1'
|
101
|
+
add_element(defaults_node, 'str', :name => 'mlt.mindf').content = '2'
|
102
|
+
end
|
103
|
+
end
|
91
104
|
end
|
92
105
|
end
|
93
106
|
end
|
@@ -9,7 +9,7 @@ module Sunspot
|
|
9
9
|
|
10
10
|
def add_element(node, name, attributes = {})
|
11
11
|
new_node = Nokogiri::XML::Node.new(name, @document)
|
12
|
-
attributes.each_pair { |name, value| new_node[name] = value }
|
12
|
+
attributes.each_pair { |name, value| new_node[name.to_s] = value }
|
13
13
|
node << new_node
|
14
14
|
new_node
|
15
15
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Query
|
3
3
|
class AbstractFieldFacet
|
4
|
+
include RSolr::Char
|
5
|
+
|
4
6
|
def initialize(field, options)
|
5
7
|
@field, @options = field, options
|
6
8
|
end
|
@@ -24,6 +26,9 @@ module Sunspot
|
|
24
26
|
if @options[:limit]
|
25
27
|
params[qualified_param('limit')] = @options[:limit].to_i
|
26
28
|
end
|
29
|
+
if @options[:prefix]
|
30
|
+
params[qualified_param('prefix')] = escape(@options[:prefix].to_s)
|
31
|
+
end
|
27
32
|
params[qualified_param('mincount')] =
|
28
33
|
case
|
29
34
|
when @options[:minimum_count] then @options[:minimum_count].to_i
|