sunspot 0.10.5 → 0.10.6

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 (55) hide show
  1. data/History.txt +13 -0
  2. data/README.rdoc +3 -3
  3. data/TODO +4 -5
  4. data/VERSION.yml +1 -1
  5. data/bin/sunspot-solr +18 -6
  6. data/lib/sunspot/dsl/field_query.rb +69 -18
  7. data/lib/sunspot/dsl/fields.rb +6 -5
  8. data/lib/sunspot/dsl/fulltext.rb +57 -1
  9. data/lib/sunspot/dsl/query.rb +30 -3
  10. data/lib/sunspot/dsl/query_facet.rb +8 -3
  11. data/lib/sunspot/dsl/search.rb +1 -1
  12. data/lib/sunspot/dsl.rb +1 -1
  13. data/lib/sunspot/field_factory.rb +6 -3
  14. data/lib/sunspot/query/abstract_field_facet.rb +43 -0
  15. data/lib/sunspot/query/date_field_facet.rb +14 -0
  16. data/lib/sunspot/query/dismax.rb +26 -7
  17. data/lib/sunspot/query/field_facet.rb +2 -122
  18. data/lib/sunspot/query/highlighting.rb +17 -5
  19. data/lib/sunspot/query/query.rb +12 -23
  20. data/lib/sunspot/query/query_facet.rb +4 -66
  21. data/lib/sunspot/query.rb +5 -1
  22. data/lib/sunspot/search/date_facet.rb +35 -0
  23. data/lib/sunspot/search/facet_row.rb +27 -0
  24. data/lib/sunspot/search/field_facet.rb +44 -0
  25. data/lib/sunspot/search/hit.rb +10 -6
  26. data/lib/sunspot/search/query_facet.rb +62 -0
  27. data/lib/sunspot/search.rb +22 -44
  28. data/lib/sunspot/setup.rb +22 -7
  29. data/lib/sunspot/type.rb +4 -0
  30. data/lib/sunspot/util.rb +8 -0
  31. data/lib/sunspot.rb +7 -6
  32. data/solr/solr/conf/solrconfig.xml +1 -2
  33. data/solr/solr/lib/locallucene.jar +0 -0
  34. data/solr/solr/lib/localsolr.jar +0 -0
  35. data/spec/api/indexer/attributes_spec.rb +5 -0
  36. data/spec/api/query/faceting_spec.rb +24 -0
  37. data/spec/api/query/fulltext_spec.rb +80 -1
  38. data/spec/api/query/highlighting_spec.rb +84 -6
  39. data/spec/api/search/faceting_spec.rb +45 -9
  40. data/spec/api/search/highlighting_spec.rb +2 -2
  41. data/spec/api/search/hits_spec.rb +5 -0
  42. data/spec/integration/faceting_spec.rb +19 -0
  43. data/spec/integration/keyword_search_spec.rb +101 -4
  44. data/spec/mocks/photo.rb +3 -0
  45. data/tasks/gemspec.rake +8 -2
  46. data/tasks/rcov.rake +2 -2
  47. metadata +9 -11
  48. data/lib/sunspot/facet.rb +0 -24
  49. data/lib/sunspot/facet_data.rb +0 -169
  50. data/lib/sunspot/facet_row.rb +0 -12
  51. data/lib/sunspot/instantiated_facet.rb +0 -39
  52. data/lib/sunspot/instantiated_facet_row.rb +0 -27
  53. data/lib/sunspot/query/fulltext_base_query.rb +0 -47
  54. data/lib/sunspot/query/query_facet_row.rb +0 -19
  55. data/lib/sunspot/query/query_field_facet.rb +0 -20
data/History.txt CHANGED
@@ -1,3 +1,16 @@
1
+ == 0.10.6 2009-11-05
2
+ * Support more dismax parameters
3
+ * Support multiple boost queries
4
+ * Allow "extra" facet rows
5
+ * Allow exclusion of fulltext fields
6
+ * Allow specification of per-field highlighting params
7
+ * Specify coordinates using block extraction
8
+ * Return empty array if no highlights available
9
+ * Get stored text fields from hits
10
+ * Update docs to reflect a requirement of at least one search type
11
+ * added --max-memory and --min-memory parameters to sunspot-solr
12
+ * LocalLucene and LocalSolr compatible with Java 1.5
13
+
1
14
  == 0.10.5 2009-10-22
2
15
  * Fix highlighting for multiple-model search
3
16
 
data/README.rdoc CHANGED
@@ -125,9 +125,9 @@ me so I can rectify the situation!
125
125
 
126
126
  == Dependencies
127
127
 
128
- 1. RSolr
129
- 2. Daemons
130
- 4. Java
128
+ 1. RSolr 0.9.6
129
+ 2. Daemons 1.x
130
+ 4. Java 1.5+
131
131
 
132
132
  Sunspot has been tested with MRI 1.8.6 and 1.8.7, REE 1.8.6, YARV 1.9.1, and
133
133
  JRuby 1.2.0
data/TODO CHANGED
@@ -1,11 +1,10 @@
1
- === 0.10 ===
2
- * Wrap everything into :q parameter when local search performed
3
- * Allow boosting without field constraints
4
- * Allow coordinates to be specified with block in setup
5
- === 0.11 ===
1
+ === 0.10.x ===
2
+ * Assumed inconsistency
6
3
  * Support all operations in batches. Make it smart.
7
4
  * Don't use more than one commits when one is equivalent
8
5
  * Preserve adds/deletes that are done after last commit
9
6
  * Don't do adds and deletes for the same document out of order
10
7
  * Don't do more than one add for the same document
11
8
  * Do use as few requests as possible within those constraints
9
+ === Future ===
10
+ * Support Solr functions (e.g. dismax :bf)
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 10
3
- :patch: 5
3
+ :patch: 6
4
4
  :major: 0
data/bin/sunspot-solr CHANGED
@@ -19,12 +19,14 @@ end
19
19
  working_directory = FileUtils.pwd
20
20
  solr_install = File.expand_path(File.join(File.dirname(__FILE__), '..', 'solr'))
21
21
 
22
- port = '8983'
23
- data_dir = File.expand_path(File.join(Dir.tmpdir, 'solr_data'))
24
- solr_home = File.join(solr_install, 'solr')
25
- pid_dir = working_directory
26
- log_file = nil
27
- log_level = 'OFF'
22
+ port = '8983'
23
+ data_dir = File.expand_path(File.join(Dir.tmpdir, 'solr_data'))
24
+ solr_home = File.join(solr_install, 'solr')
25
+ pid_dir = working_directory
26
+ log_file = nil
27
+ log_level = 'OFF'
28
+ min_memory = '128m'
29
+ max_memory = '512m'
28
30
 
29
31
  OptionParser.new do |opts|
30
32
  opts.banner = "Usage: sunspot-solr start [options]"
@@ -52,6 +54,14 @@ OptionParser.new do |opts|
52
54
  opts.on '--log-file=LOG_FILE', 'Path to Solr log file' do |lf|
53
55
  log_file = File.expand_path(lf)
54
56
  end
57
+
58
+ opts.on '--max-memory=MEMORY', 'Specify the maximum size of the memory allocation pool' do |mm|
59
+ max_memory = mm
60
+ end
61
+
62
+ opts.on '--min-memory=MEMORY', 'Specify the initial size of the memory allocation pool' do |mm|
63
+ min_memory = mm
64
+ end
55
65
  end.parse!
56
66
 
57
67
  options = { :dir_mode => :normal, :dir => pid_dir }
@@ -72,6 +82,8 @@ end
72
82
  Daemons.run_proc('sunspot-solr', options) do
73
83
  FileUtils.cd(solr_install) do
74
84
  args = ['java']
85
+ args << "-Xms#{min_memory}"
86
+ args << "-Xmx#{max_memory}"
75
87
  args << "-Djetty.port=#{port}" if port
76
88
  args << "-Dsolr.data.dir=#{data_dir}" if data_dir
77
89
  args << "-Dsolr.solr.home=#{solr_home}" if solr_home
@@ -6,8 +6,8 @@ module Sunspot
6
6
  # query DSL.
7
7
  #
8
8
  class FieldQuery < Scope
9
- def initialize(query, setup)
10
- @query = query
9
+ def initialize(search, query, setup) #:nodoc:
10
+ @search, @query = search, query
11
11
  super(query.scope, setup)
12
12
  end
13
13
 
@@ -58,39 +58,90 @@ module Sunspot
58
58
  # :zeros<Boolean>::
59
59
  # Return facet rows for which there are no matches (equivalent to
60
60
  # :minimum_count => 0). Default is false.
61
+ # :extra<Symbol,Array>::
62
+ # One or more of :any and :none. :any returns a facet row with a count
63
+ # of all matching documents that have some value for this field. :none
64
+ # returns a facet row with a count of all matching documents that have
65
+ # no value for this field. The facet row(s) corresponding to the extras
66
+ # have a value of the symbol passed.
61
67
  #
62
68
  def facet(*field_names, &block)
69
+ options = Sunspot::Util.extract_options_from(field_names)
70
+
63
71
  if block
64
- options =
65
- if field_names.last.is_a?(Hash)
66
- field_names.pop
67
- else
68
- {}
69
- end
70
72
  if field_names.length != 1
71
73
  raise(
72
74
  ArgumentError,
73
75
  "wrong number of arguments (#{field_names.length} for 1)"
74
76
  )
75
77
  end
76
- name = field_names.first
77
- DSL::QueryFacet.new(@query.add_query_facet(name, options), @setup).instance_eval(&block)
78
+ search_facet = @search.add_query_facet(field_names.first, options)
79
+ Sunspot::Util.instance_eval_or_call(
80
+ QueryFacet.new(@query, @setup, search_facet),
81
+ &block
82
+ )
83
+ elsif options[:only]
84
+ field_names.each do |field_name|
85
+ field = @setup.field(field_name)
86
+ search_facet = @search.add_field_facet(field, options)
87
+ Array(options[:only]).each do |value|
88
+ facet = Sunspot::Query::QueryFacet.new
89
+ facet.add_restriction(field, Sunspot::Query::Restriction::EqualTo, value)
90
+ @query.add_query_facet(facet)
91
+ search_facet.add_row(value, facet.to_boolean_phrase)
92
+ end
93
+ end
78
94
  else
79
- options =
80
- if field_names.last.is_a?(Hash)
81
- field_names.pop
82
- else
83
- {}
95
+ field_names.each do |field_name|
96
+ search_facet = nil
97
+ field = @setup.field(field_name)
98
+ facet =
99
+ if options[:time_range]
100
+ unless field.type == Sunspot::Type::TimeType
101
+ raise(
102
+ ArgumentError,
103
+ ':time_range can only be specified for Date or Time fields'
104
+ )
105
+ end
106
+ search_facet = @search.add_date_facet(field, options)
107
+ Sunspot::Query::DateFieldFacet.new(field, options)
108
+ else
109
+ search_facet = @search.add_field_facet(field)
110
+ Sunspot::Query::FieldFacet.new(field, options)
111
+ end
112
+ @query.add_field_facet(facet)
113
+ Array(options[:extra]).each do |extra|
114
+ extra_facet = Sunspot::Query::QueryFacet.new
115
+ case extra
116
+ when :any
117
+ extra_facet.add_negated_restriction(
118
+ field,
119
+ Sunspot::Query::Restriction::EqualTo,
120
+ nil
121
+ )
122
+ when :none
123
+ extra_facet.add_restriction(
124
+ field,
125
+ Sunspot::Query::Restriction::EqualTo,
126
+ nil
127
+ )
128
+ else
129
+ raise(
130
+ ArgumentError,
131
+ "Allowed values for :extra are :any and :none"
132
+ )
133
+ end
134
+ search_facet.add_row(extra, extra_facet.to_boolean_phrase)
135
+ @query.add_query_facet(extra_facet)
84
136
  end
85
- for field_name in field_names
86
- @query.add_field_facet(@setup.field(field_name), options)
87
137
  end
88
138
  end
89
139
  end
90
140
 
91
141
  def dynamic(base_name, &block)
142
+ dynamic_field_factory = @setup.dynamic_field_factory(base_name)
92
143
  Sunspot::Util.instance_eval_or_call(
93
- FieldQuery.new(@query, @setup.dynamic_field_factory(base_name)),
144
+ FieldQuery.new(@search, @query, dynamic_field_factory),
94
145
  &block
95
146
  )
96
147
  end
@@ -44,12 +44,13 @@ module Sunspot
44
44
  end
45
45
 
46
46
  #
47
- # Specify a method that returns the geographical coordinates associated
48
- # with the document. The object returned must respond to #first and #last
49
- # (e.g., a two-element Array); or to #lat and one of #lng, #lon, or #long
47
+ # Specify a method or block that returns the geographical coordinates
48
+ # associated with the document. The object returned must respond to #first
49
+ # and #last (e.g., a two-element Array); or to #lat and one of #lng, #lon,
50
+ # or #long
50
51
  #
51
- def coordinates(name)
52
- @setup.set_coordinates_field(name)
52
+ def coordinates(name = nil, &block)
53
+ @setup.set_coordinates_field(name, &block)
53
54
  end
54
55
 
55
56
  #
@@ -5,9 +5,12 @@ module Sunspot
5
5
  # handler.
6
6
  #
7
7
  class Fulltext
8
+ attr_reader :exclude_fields #:nodoc:
9
+
8
10
  def initialize(query, setup) #:nodoc:
9
11
  @query, @setup = query, setup
10
12
  @fields_added = false
13
+ @exclude_fields = []
11
14
  end
12
15
 
13
16
  #
@@ -46,6 +49,14 @@ module Sunspot
46
49
  end
47
50
  end
48
51
 
52
+ #
53
+ # Exclude the given fields from the search. All fields that are configured
54
+ # for the types under search and not listed here will be searched.
55
+ #
56
+ def exclude_fields(*field_names)
57
+ @exclude_fields.concat(field_names)
58
+ end
59
+
49
60
  #
50
61
  # Enable keyword highlighting for this search. By default, the fields
51
62
  # under search will be highlighted; you may also may pass one or more
@@ -86,7 +97,7 @@ module Sunspot
86
97
  fields = []
87
98
  args.each { |field_name| fields.concat(@setup.text_fields(field_name)) }
88
99
 
89
- @query.set_highlight(fields, options)
100
+ @query.add_highlight(fields, options)
90
101
  end
91
102
 
92
103
  #
@@ -115,12 +126,26 @@ module Sunspot
115
126
  end
116
127
  end
117
128
 
129
+ #
130
+ # The maximum number of words that can appear between search terms for a
131
+ # field to qualify for phrase field boost. See #query_phrase_slop for
132
+ # examples. Phrase slop is only meaningful if phrase fields are specified
133
+ # (see #phrase_fields), and it does not have an effect on which results
134
+ # are returned; only on what their respective boosts are.
135
+ #
136
+ def phrase_slop(slop)
137
+ @query.phrase_slop = slop
138
+ end
139
+
118
140
  #
119
141
  # Boost queries allow specification of an arbitrary scope for which
120
142
  # matching documents should receive an extra boost. The block is evaluated
121
143
  # in the usual scope DSL, and field names are attribute fields, not text
122
144
  # fields, as in other scope.
123
145
  #
146
+ # This method can be called more than once for different boost queries
147
+ # with different boosts.
148
+ #
124
149
  # === Example
125
150
  #
126
151
  # Sunspot.search(Post) do
@@ -159,6 +184,37 @@ module Sunspot
159
184
  end
160
185
  end
161
186
  end
187
+
188
+ #
189
+ # The minimum number of search terms that a result must match. By
190
+ # default, all search terms must match; if the number of search terms
191
+ # is less than this number, the default behavior applies.
192
+ #
193
+ def minimum_match(minimum_match)
194
+ @query.minimum_match = minimum_match
195
+ end
196
+
197
+ #
198
+ # The number of words that can appear between the words in a
199
+ # user-entered phrase (i.e., keywords in quotes) and still match. For
200
+ # instance, in a search for "\"great pizza\"" with a query phrase slop of
201
+ # 1, "great pizza" and "great big pizza" will match, but "great monster of
202
+ # a pizza" will not. Default behavior is a query phrase slop of zero.
203
+ #
204
+ def query_phrase_slop(slop)
205
+ @query.query_phrase_slop = slop
206
+ end
207
+
208
+ #
209
+ # A tiebreaker coefficient for scores derived from subqueries that are
210
+ # lower-scoring than the maximum score subquery. Typically a near-zero
211
+ # value is useful. See
212
+ # http://wiki.apache.org/solr/DisMaxRequestHandler#tie_.28Tie_breaker.29
213
+ # for more information.
214
+ #
215
+ def tie(tie)
216
+ @query.tie = tie
217
+ end
162
218
 
163
219
  def fields_added? #:nodoc:
164
220
  @fields_added
@@ -34,6 +34,22 @@ module Sunspot
34
34
  # If true, perform keyword highlighting on all searched fields. If an
35
35
  # array of field names, perform highlighting on the specified fields.
36
36
  # This can also be called from within the fulltext block.
37
+ # :minimum_match<Integer>::
38
+ # The minimum number of search terms that a result must match. By
39
+ # default, all search terms must match; if the number of search terms
40
+ # is less than this number, the default behavior applies.
41
+ # :tie<Float>::
42
+ # A tiebreaker coefficient for scores derived from subqueries that are
43
+ # lower-scoring than the maximum score subquery. Typically a near-zero
44
+ # value is useful. See
45
+ # http://wiki.apache.org/solr/DisMaxRequestHandler#tie_.28Tie_breaker.29
46
+ # for more information.
47
+ # :query_phrase_slop<Integer>::
48
+ # The number of words that can appear between the words in a
49
+ # user-entered phrase (i.e., keywords in quotes) and still match. For
50
+ # instance, in a search for "\"great pizza\"" with a phrase slop of 1,
51
+ # "great pizza" and "great big pizza" will match, but "great monster of
52
+ # a pizza" will not. Default behavior is a query phrase slop of zero.
37
53
  #
38
54
  def fulltext(keywords, options = {}, &block)
39
55
  if keywords && !(keywords.to_s =~ /^\s*$/)
@@ -45,15 +61,24 @@ module Sunspot
45
61
  end
46
62
  end
47
63
  end
64
+ if minimum_match = options.delete(:minimum_match)
65
+ fulltext_query.minimum_match = minimum_match.to_i
66
+ end
67
+ if tie = options.delete(:tie)
68
+ fulltext_query.tie = tie.to_f
69
+ end
70
+ if query_phrase_slop = options.delete(:query_phrase_slop)
71
+ fulltext_query.query_phrase_slop = query_phrase_slop.to_i
72
+ end
48
73
  if highlight_field_names = options.delete(:highlight)
49
74
  if highlight_field_names == true
50
- fulltext_query.set_highlight
75
+ fulltext_query.add_highlight
51
76
  else
52
77
  highlight_fields = []
53
78
  Array(highlight_field_names).each do |field_name|
54
79
  highlight_fields.concat(@setup.text_fields(field_name))
55
80
  end
56
- fulltext_query.set_highlight(highlight_fields)
81
+ fulltext_query.add_highlight(highlight_fields)
57
82
  end
58
83
  end
59
84
  if block && fulltext_query
@@ -66,7 +91,9 @@ module Sunspot
66
91
  if !field_names && (!fulltext_dsl || !fulltext_dsl.fields_added?)
67
92
  @setup.all_text_fields.each do |field|
68
93
  unless fulltext_query.has_fulltext_field?(field)
69
- fulltext_query.add_fulltext_field(field, field.default_boost)
94
+ unless fulltext_dsl && fulltext_dsl.exclude_fields.include?(field.name)
95
+ fulltext_query.add_fulltext_field(field, field.default_boost)
96
+ end
70
97
  end
71
98
  end
72
99
  end
@@ -5,8 +5,8 @@ module Sunspot
5
5
  # method.
6
6
  #
7
7
  class QueryFacet
8
- def initialize(query_facet, setup) #:nodoc:
9
- @query_facet, @setup = query_facet, setup
8
+ def initialize(query, setup, facet) #:nodoc:
9
+ @query, @setup, @facet = query, setup, facet
10
10
  end
11
11
 
12
12
  #
@@ -24,7 +24,12 @@ module Sunspot
24
24
  # An object used to identify this facet row in the results.
25
25
  #
26
26
  def row(label, &block)
27
- Scope.new(@query_facet.add_row(label), @setup).instance_eval(&block)
27
+ query_facet = Sunspot::Query::QueryFacet.new
28
+ Sunspot::Util.instance_eval_or_call(
29
+ Scope.new(@query.add_query_facet(query_facet), @setup),
30
+ &block
31
+ )
32
+ @facet.add_row(label, query_facet.to_boolean_phrase)
28
33
  end
29
34
  end
30
35
  end
@@ -8,7 +8,7 @@ module Sunspot
8
8
  class Search < Query
9
9
  def initialize(search, setup) #:nodoc:
10
10
  @search = search
11
- super(search.query, setup)
11
+ super(search, search.query, setup)
12
12
  end
13
13
 
14
14
  #
data/lib/sunspot/dsl.rb CHANGED
@@ -1,4 +1,4 @@
1
- %w(fields scope field_query query fulltext query_facet restriction
1
+ %w(fields scope field_query query query_facet fulltext restriction
2
2
  search).each do |file|
3
3
  require File.join(File.dirname(__FILE__), 'dsl', file)
4
4
  end
@@ -123,10 +123,13 @@ module Sunspot
123
123
  end
124
124
  end
125
125
 
126
- #XXX Right now this doubles as a Field and a FieldFactory - good idea?
127
126
  class Coordinates
128
- def initialize(name)
129
- @data_extractor = DataExtractor::AttributeExtractor.new(name)
127
+ def initialize(name = nil, &block)
128
+ if block
129
+ @data_extractor = DataExtractor::BlockExtractor.new(&block)
130
+ else
131
+ @data_extractor = DataExtractor::AttributeExtractor.new(name)
132
+ end
130
133
  end
131
134
 
132
135
  def populate_document(document, model)
@@ -0,0 +1,43 @@
1
+ module Sunspot
2
+ module Query
3
+ class AbstractFieldFacet
4
+ def initialize(field, options)
5
+ @field, @options = field, options
6
+ end
7
+
8
+ def to_params
9
+ params = {
10
+ :facet => 'true',
11
+ }
12
+ case @options[:sort]
13
+ when :count
14
+ params[qualified_param('sort')] = 'true'
15
+ when :index
16
+ params[qualified_param('sort')] = 'false'
17
+ when nil
18
+ else
19
+ raise(
20
+ ArgumentError,
21
+ "#{@options[:sort].inspect} is not an allowed value for :sort. Allowed options are :count and :index"
22
+ )
23
+ end
24
+ if @options[:limit]
25
+ params[qualified_param('limit')] = @options[:limit].to_i
26
+ end
27
+ params[qualified_param('mincount')] =
28
+ case
29
+ when @options[:minimum_count] then @options[:minimum_count].to_i
30
+ when @options[:zeros] then 0
31
+ else 1
32
+ end
33
+ params
34
+ end
35
+
36
+ private
37
+
38
+ def qualified_param(param)
39
+ :"f.#{@field.indexed_name}.facet.#{param}"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ module Sunspot
2
+ module Query
3
+ class DateFieldFacet < AbstractFieldFacet
4
+ def to_params
5
+ params = super
6
+ params[:"facet.date"] = [@field.indexed_name]
7
+ params[qualified_param('date.start')] = @field.to_indexed(@options[:time_range].first)
8
+ params[qualified_param('date.end')] = @field.to_indexed(@options[:time_range].last)
9
+ params[qualified_param('date.gap')] = "+#{@options[:time_interval] || 86400}SECONDS"
10
+ params
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,9 +1,13 @@
1
1
  module Sunspot
2
2
  module Query
3
3
  class Dismax
4
+ attr_writer :minimum_match, :phrase_slop, :query_phrase_slop, :tie
5
+
4
6
  def initialize(keywords)
5
7
  @keywords = keywords
6
8
  @fulltext_fields = {}
9
+ @boost_queries = []
10
+ @highlights = []
7
11
  end
8
12
 
9
13
  #
@@ -17,11 +21,25 @@ module Sunspot
17
21
  if @phrase_fields
18
22
  params[:pf] = @phrase_fields.map { |field| field.to_boosted_field }.join(' ')
19
23
  end
20
- if @boost_query
21
- params[:bq] = @boost_query.to_boolean_phrase
24
+ unless @boost_queries.empty?
25
+ params[:bq] = @boost_queries.map do |boost_query|
26
+ boost_query.to_boolean_phrase
27
+ end
28
+ end
29
+ if @minimum_match
30
+ params[:mm] = @minimum_match
31
+ end
32
+ if @phrase_slop
33
+ params[:ps] = @phrase_slop
34
+ end
35
+ if @query_phrase_slop
36
+ params[:qs] = @query_phrase_slop
37
+ end
38
+ if @tie
39
+ params[:tie] = @tie
22
40
  end
23
- if @highlight
24
- Sunspot::Util.deep_merge!(params, @highlight.to_params)
41
+ @highlights.each do |highlight|
42
+ Sunspot::Util.deep_merge!(params, highlight.to_params)
25
43
  end
26
44
  params
27
45
  end
@@ -30,7 +48,8 @@ module Sunspot
30
48
  # Assign a new boost query and return it.
31
49
  #
32
50
  def create_boost_query(factor)
33
- @boost_query = BoostQuery.new(factor)
51
+ @boost_queries << boost_query = BoostQuery.new(factor)
52
+ boost_query
34
53
  end
35
54
 
36
55
  #
@@ -53,8 +72,8 @@ module Sunspot
53
72
  # Highlighting object won't pass field names at all, which means
54
73
  # the dismax's :qf parameter will be used by Solr.
55
74
  #
56
- def set_highlight(fields=[], options={})
57
- @highlight = Highlighting.new(fields, options)
75
+ def add_highlight(fields=[], options={})
76
+ @highlights << Highlighting.new(fields, options)
58
77
  end
59
78
 
60
79
  #