sunspot 1.0.5 → 1.1.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.
Files changed (90) hide show
  1. data/README.rdoc +3 -0
  2. data/TODO +6 -5
  3. data/bin/sunspot-solr +4 -0
  4. data/installer/config/schema.yml +24 -0
  5. data/lib/sunspot/composite_setup.rb +14 -0
  6. data/lib/sunspot/dsl/adjustable.rb +47 -0
  7. data/lib/sunspot/dsl/fulltext.rb +23 -8
  8. data/lib/sunspot/dsl/function.rb +14 -0
  9. data/lib/sunspot/dsl/functional.rb +41 -0
  10. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  11. data/lib/sunspot/dsl/paginatable.rb +28 -0
  12. data/lib/sunspot/dsl/search.rb +1 -1
  13. data/lib/sunspot/dsl/{query.rb → standard_query.rb} +4 -49
  14. data/lib/sunspot/dsl.rb +3 -2
  15. data/lib/sunspot/field.rb +16 -2
  16. data/lib/sunspot/indexer.rb +1 -1
  17. data/lib/sunspot/installer/schema_builder.rb +1 -1
  18. data/lib/sunspot/installer/solrconfig_updater.rb +13 -0
  19. data/lib/sunspot/installer/task_helper.rb +1 -1
  20. data/lib/sunspot/query/abstract_field_facet.rb +5 -0
  21. data/lib/sunspot/query/boost_query.rb +5 -1
  22. data/lib/sunspot/query/{query.rb → common_query.rb} +26 -20
  23. data/lib/sunspot/query/composite_fulltext.rb +31 -0
  24. data/lib/sunspot/query/dismax.rb +45 -6
  25. data/lib/sunspot/query/function_query.rb +52 -0
  26. data/lib/sunspot/query/more_like_this.rb +60 -0
  27. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  28. data/lib/sunspot/query/standard_query.rb +20 -0
  29. data/lib/sunspot/query/text_field_boost.rb +2 -0
  30. data/lib/sunspot/query.rb +3 -2
  31. data/lib/sunspot/search/abstract_search.rb +302 -0
  32. data/lib/sunspot/search/date_facet.rb +1 -1
  33. data/lib/sunspot/search/facet_row.rb +1 -1
  34. data/lib/sunspot/search/field_facet.rb +1 -1
  35. data/lib/sunspot/search/highlight.rb +1 -1
  36. data/lib/sunspot/search/hit.rb +1 -1
  37. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  38. data/lib/sunspot/search/query_facet.rb +1 -1
  39. data/lib/sunspot/search/standard_search.rb +21 -0
  40. data/lib/sunspot/search.rb +3 -288
  41. data/lib/sunspot/server.rb +8 -4
  42. data/lib/sunspot/session.rb +30 -2
  43. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +1 -1
  44. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +9 -0
  45. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +9 -2
  46. data/lib/sunspot/setup.rb +32 -3
  47. data/lib/sunspot/type.rb +74 -0
  48. data/lib/sunspot/util.rb +3 -2
  49. data/lib/sunspot/version.rb +1 -1
  50. data/lib/sunspot.rb +9 -1
  51. data/solr/solr/conf/schema.xml +12 -0
  52. data/solr/solr/conf/solrconfig.xml +6 -0
  53. data/spec/api/indexer/attributes_spec.rb +9 -3
  54. data/spec/api/indexer/fulltext_spec.rb +2 -2
  55. data/spec/api/indexer/removal_spec.rb +1 -1
  56. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  57. data/spec/api/query/{connectives_spec.rb → connectives_examples.rb} +19 -19
  58. data/spec/api/query/{dynamic_fields_spec.rb → dynamic_fields_examples.rb} +33 -17
  59. data/spec/api/query/{faceting_spec.rb → faceting_examples.rb} +146 -43
  60. data/spec/api/query/{fulltext_spec.rb → fulltext_examples.rb} +81 -47
  61. data/spec/api/query/function_spec.rb +70 -0
  62. data/spec/api/query/{highlighting_spec.rb → highlighting_examples.rb} +27 -27
  63. data/spec/api/query/{local_spec.rb → local_examples.rb} +5 -5
  64. data/spec/api/query/more_like_this_spec.rb +140 -0
  65. data/spec/api/query/{ordering_pagination_spec.rb → ordering_pagination_examples.rb} +16 -16
  66. data/spec/api/query/{scope_spec.rb → scope_examples.rb} +44 -61
  67. data/spec/api/query/standard_spec.rb +28 -0
  68. data/spec/api/query/{text_field_scoping_spec.rb → text_field_scoping_examples.rb} +5 -5
  69. data/spec/api/search/dynamic_fields_spec.rb +6 -0
  70. data/spec/api/search/faceting_spec.rb +10 -10
  71. data/spec/api/search/hits_spec.rb +1 -1
  72. data/spec/api/search/results_spec.rb +10 -0
  73. data/spec/api/server_spec.rb +6 -0
  74. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +2 -2
  75. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +17 -0
  76. data/spec/api/spec_helper.rb +2 -0
  77. data/spec/helpers/query_helper.rb +25 -0
  78. data/spec/helpers/search_helper.rb +4 -0
  79. data/spec/integration/faceting_spec.rb +8 -0
  80. data/spec/integration/keyword_search_spec.rb +75 -3
  81. data/spec/integration/local_search_spec.rb +1 -1
  82. data/spec/integration/more_like_this_spec.rb +43 -0
  83. data/spec/mocks/comment.rb +1 -1
  84. data/spec/mocks/connection.rb +27 -12
  85. data/spec/mocks/post.rb +5 -4
  86. data/spec/spec_helper.rb +4 -21
  87. data/tasks/gemspec.rake +1 -1
  88. metadata +39 -27
  89. data/spec/api/query/adjust_params_spec.rb +0 -37
  90. 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.0 ===
2
- * new_search should accept block
1
+ === Sunspot 1.1.x ===
2
+ * commitWithin (needs support from RSolr, currently available in master)
3
+ * commit options (non-blocking, etc.)
3
4
 
4
- === Future ===
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
@@ -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
@@ -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. The block is evaluated
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
- def boost(factor, &block)
162
- Sunspot::Util.instance_eval_or_call(
163
- Scope.new(@query.create_boost_query(factor), @setup),
164
- &block
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
@@ -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 < Query
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 Query < FieldQuery
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.set_fulltext(keywords)
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 query query_facet fulltext restriction
2
- search).each do |file|
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
 
@@ -54,7 +54,7 @@ module Sunspot
54
54
  if clazz
55
55
  @connection.delete_by_query("type:#{escape(clazz.name)}")
56
56
  else
57
- @connection.delete_by_query("type:[* TO *]")
57
+ @connection.delete_by_query("*:*")
58
58
  end
59
59
  end
60
60
 
@@ -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.node_type == :comment && comment.content =~ /Sunspot/
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
@@ -13,7 +13,11 @@ module Sunspot
13
13
  end
14
14
 
15
15
  def to_boolean_phrase
16
- "#{super}^#{@boost}"
16
+ if @boost.is_a?(FunctionQuery)
17
+ "#{@boost}"
18
+ else
19
+ "#{super}^#{@boost}"
20
+ end
17
21
  end
18
22
  end
19
23
  end