Commit afed3cd8148668fc0b76ef08bf15d3ccd7662311
1 parent
5a19d5ad
Exists in
master
and in
21 other branches
Changed to boost_by_distance
Showing
5 changed files
with
32 additions
and
40 deletions
Show diff stats
CHANGELOG.md
README.md
... | ... | @@ -616,16 +616,19 @@ Bounded by a box |
616 | 616 | City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} |
617 | 617 | ``` |
618 | 618 | |
619 | -Modify search score by proximity to a point: | |
619 | +### Boost By Distance [master] | |
620 | + | |
621 | +Boost results by distance - closer results are boosted more | |
620 | 622 | |
621 | 623 | ```ruby |
622 | -City.search "san", proximity_factor: { field: :location, origin: [37, -122] } # field and origin mandatory | |
623 | -City.search "san", proximity_factor: { field: :location, origin: [37, -122], function: :linear, scale: "30mi", decay: 0.5 } # at 30mi, decrease score by 50% | |
624 | +City.search "san", boost_by_distance: {field: :location, origin: [37, -122]} | |
624 | 625 | ``` |
625 | 626 | |
626 | -The difference between where with a geo_point and proximity_factor is that the former is a hard cutoff that simply includes or excludes results but has no impact on the order of results, whereas the latter smoothly modifies the search score so that the results with the best match for the query text and the distance are returned. | |
627 | +Also supports [additional options](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions) | |
627 | 628 | |
628 | -See [more details on modifying the score by proximity](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions). | |
629 | +```ruby | |
630 | +City.search "san", boost_by_distance: {field: :location, origin: [37, -122], function: :linear, scale: "30mi", decay: 0.5} | |
631 | +``` | |
629 | 632 | |
630 | 633 | ## Inheritance |
631 | 634 | ... | ... |
lib/searchkick/query.rb
... | ... | @@ -209,39 +209,27 @@ module Searchkick |
209 | 209 | } |
210 | 210 | end |
211 | 211 | |
212 | - if custom_filters.any? | |
213 | - payload = { | |
214 | - function_score: { | |
215 | - functions: custom_filters, | |
216 | - query: payload, | |
217 | - score_mode: "sum" | |
212 | + boost_by_distance = options[:boost_by_distance] | |
213 | + if boost_by_distance | |
214 | + boost_by_distance = {function: :gauss, scale: "5mi"}.merge(boost_by_distance) | |
215 | + if !boost_by_distance[:field] or !boost_by_distance[:origin] | |
216 | + raise ArgumentError, "boost_by_distance requires :field and :origin" | |
217 | + end | |
218 | + function_params = boost_by_distance.select{|k,v| [:origin, :scale, :offset, :decay].include?(k) } | |
219 | + function_params[:origin] = function_params[:origin].reverse | |
220 | + custom_filters << { | |
221 | + boost_by_distance[:function] => { | |
222 | + boost_by_distance[:field] => function_params | |
218 | 223 | } |
219 | 224 | } |
220 | 225 | end |
221 | 226 | |
222 | - # Modify the query scoring by proximity to a geo point | |
223 | - if options[:proximity_factor] | |
224 | - proximity_factor = { function: :gauss, score_mode: :multiply, scale: "5mi" }.merge(options[:proximity_factor]) | |
225 | - (proximity_factor[:field] and proximity_factor[:origin]) or raise ArgumentError, "query() option :proximity_factor must contain at least :field and :origin" | |
226 | - | |
227 | - field = proximity_factor[:field] | |
228 | - function = proximity_factor[:function] | |
229 | - function_params = proximity_factor.select { |k,v| [:origin, :scale, :offset, :decay].include? k } | |
230 | - # Conform to GeoJSON convention of [longitude, latitude] | |
231 | - function_params[:origin] = function_params[:origin].reverse | |
232 | - score_mode = proximity_factor[:score_mode] | |
233 | - | |
227 | + if custom_filters.any? | |
234 | 228 | payload = { |
235 | 229 | function_score: { |
236 | - functions: [ | |
237 | - { | |
238 | - function => { | |
239 | - field => function_params | |
240 | - } | |
241 | - } | |
242 | - ], | |
230 | + functions: custom_filters, | |
243 | 231 | query: payload, |
244 | - score_mode: score_mode | |
232 | + score_mode: "sum" | |
245 | 233 | } |
246 | 234 | } |
247 | 235 | end | ... | ... |
test/boost_test.rb
... | ... | @@ -104,4 +104,13 @@ class TestBoost < Minitest::Test |
104 | 104 | assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}} |
105 | 105 | end |
106 | 106 | |
107 | + def test_boost_by_distance | |
108 | + store [ | |
109 | + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | |
110 | + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}, | |
111 | + {name: "San Marino", latitude: 43.9333, longitude: 12.4667} | |
112 | + ] | |
113 | + assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {field: :location, origin: [37, -122], scale: "1000mi"} | |
114 | + end | |
115 | + | |
107 | 116 | end | ... | ... |
test/sql_test.rb
... | ... | @@ -261,15 +261,6 @@ class TestSql < Minitest::Test |
261 | 261 | assert_search "product", ["Product"], where: {latitude: {gt: 99}} |
262 | 262 | end |
263 | 263 | |
264 | - def test_proximity | |
265 | - store [ | |
266 | - {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | |
267 | - {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}, | |
268 | - {name: "San Marino", latitude: 43.9333, longitude: 12.4667} | |
269 | - ] | |
270 | - assert_order "san", ["San Francisco", "San Antonio", "San Marino"], proximity_factor: {field: :location, origin: [37, -122]} | |
271 | - end | |
272 | - | |
273 | 264 | # load |
274 | 265 | |
275 | 266 | def test_load_default | ... | ... |