Commit 309efcda7d5145a6a9be8cadcbbb6d5fff8c28bf
Exists in
master
and in
21 other branches
Merge branch 'richardking-master'
Showing
3 changed files
with
63 additions
and
21 deletions
Show diff stats
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 < 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 | ... | ... |