Commit 309efcda7d5145a6a9be8cadcbbb6d5fff8c28bf

Authored by Andrew Kane
2 parents f8714d22 c1b57c72

Merge branch 'richardking-master'

lib/searchkick/query.rb
... ... @@ -15,9 +15,6 @@ module Searchkick
15 15 @term = term
16 16 @options = options
17 17  
18   - below12 = Gem::Version.new(Searchkick.server_version) < Gem::Version.new("1.2.0")
19   - below14 = Gem::Version.new(Searchkick.server_version) < Gem::Version.new("1.4.0")
20   -
21 18 boost_fields = {}
22 19 fields =
23 20 if options[:fields]
... ... @@ -134,7 +131,7 @@ module Searchkick
134 131 if conversions_field && options[:conversions] != false
135 132 # wrap payload in a bool query
136 133 script_score =
137   - if below12
  134 + if below12?
138 135 {script_score: {script: "doc['count'].value"}}
139 136 else
140 137 {field_value_factor: {field: "count"}}
... ... @@ -165,31 +162,21 @@ module Searchkick
165 162 end
166 163  
167 164 custom_filters = []
  165 + multiply_filters = []
168 166  
169 167 boost_by = options[:boost_by] || {}
  168 +
170 169 if boost_by.is_a?(Array)
171 170 boost_by = Hash[boost_by.map { |f| [f, {factor: 1}] }]
  171 + elsif boost_by.is_a?(Hash)
  172 + multiply_by, boost_by = boost_by.partition { |k,v| v[:boost_mode] == "multiply" }.map{ |i| Hash[i] }
172 173 end
173 174 if options[:boost]
174 175 boost_by[options[:boost]] = {factor: 1}
175 176 end
176 177  
177   - boost_by.each do |field, value|
178   - script_score =
179   - if below12
180   - {script_score: {script: "#{value[:factor].to_f} * log(doc['#{field}'].value + 2.718281828)"}}
181   - else
182   - {field_value_factor: {field: field, factor: value[:factor].to_f, modifier: "ln2p"}}
183   - end
184   -
185   - custom_filters << {
186   - filter: {
187   - exists: {
188   - field: field
189   - }
190   - }
191   - }.merge(script_score)
192   - end
  178 + custom_filters.concat boost_filters(boost_by, log: true)
  179 + multiply_filters.concat boost_filters(multiply_by || {})
193 180  
194 181 boost_where = options[:boost_where] || {}
195 182 if options[:user_id] && personalize_field
... ... @@ -238,6 +225,16 @@ module Searchkick
238 225 }
239 226 end
240 227  
  228 + if multiply_filters.any?
  229 + payload = {
  230 + function_score: {
  231 + functions: multiply_filters,
  232 + query: payload,
  233 + score_mode: "multiply"
  234 + }
  235 + }
  236 + end
  237 +
241 238 payload = {
242 239 query: payload,
243 240 size: per_page,
... ... @@ -295,7 +292,7 @@ module Searchkick
295 292 payload[:facets][field] = {
296 293 terms_stats: {
297 294 key_field: field,
298   - value_script: below14 ? "doc.score" : "_score",
  295 + value_script: below14? ? "doc.score" : "_score",
299 296 size: size
300 297 }
301 298 }
... ... @@ -568,5 +565,37 @@ module Searchkick
568 565 }
569 566 end
570 567  
  568 + def boost_filters(boost_by, options = {})
  569 + boost_by.map do |field, value|
  570 + log = value.key?(:log) ? value[:log] : options[:log]
  571 + script_score =
  572 + if below12?
  573 + script = log ? "log(doc['#{field}'].value + 2.718281828)" : "doc['#{field}'].value"
  574 + {script_score: {script: "#{value[:factor].to_f} * #{script}"}}
  575 + else
  576 + {field_value_factor: {field: field, factor: value[:factor].to_f, modifier: log ? "ln2p" : nil}}
  577 + end
  578 +
  579 + {
  580 + filter: {
  581 + exists: {
  582 + field: field
  583 + }
  584 + }
  585 + }.merge(script_score)
  586 + end
  587 + end
  588 +
  589 + def below12?
  590 + below_version?("1.2.0")
  591 + end
  592 +
  593 + def below14?
  594 + below_version?("1.4.0")
  595 + end
  596 +
  597 + def below_version?(version)
  598 + Gem::Version.new(Searchkick.server_version) < Gem::Version.new(version)
  599 + end
571 600 end
572 601 end
... ...
test/boost_test.rb
... ... @@ -101,6 +101,16 @@ class TestBoost &lt; Minitest::Test
101 101 assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: {orders_count: {factor: 10}}
102 102 end
103 103  
  104 + def test_boost_by_boost_mode_multiply
  105 + store [
  106 + {name: "Tomato A", found_rate: 0.9},
  107 + {name: "Tomato B"},
  108 + {name: "Tomato C", found_rate: 0.5}
  109 + ]
  110 +
  111 + assert_order "tomato", ["Tomato B", "Tomato A", "Tomato C"], boost_by: {found_rate: {boost_mode: "multiply"}}
  112 + end
  113 +
104 114 def test_boost_where
105 115 store [
106 116 {name: "Tomato A"},
... ...
test/test_helper.rb
... ... @@ -51,6 +51,7 @@ if defined?(Mongoid)
51 51 field :in_stock, type: Boolean
52 52 field :backordered, type: Boolean
53 53 field :orders_count, type: Integer
  54 + field :found_rate, type: BigDecimal
54 55 field :price, type: Integer
55 56 field :color
56 57 field :latitude, type: BigDecimal
... ... @@ -90,6 +91,7 @@ elsif defined?(NoBrainer)
90 91 field :in_stock, type: Boolean
91 92 field :backordered, type: Boolean
92 93 field :orders_count, type: Integer
  94 + field :found_rate
93 95 field :price, type: Integer
94 96 field :color, type: String
95 97 field :latitude
... ... @@ -139,6 +141,7 @@ else
139 141 t.boolean :in_stock
140 142 t.boolean :backordered
141 143 t.integer :orders_count
  144 + t.decimal :found_rate
142 145 t.integer :price
143 146 t.string :color
144 147 t.decimal :latitude, precision: 10, scale: 7
... ...