sunspot 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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