Commit afed3cd8148668fc0b76ef08bf15d3ccd7662311

Authored by Andrew Kane
1 parent 5a19d5ad

Changed to boost_by_distance

1 ## 0.8.4 [unreleased] 1 ## 0.8.4 [unreleased]
2 2
  3 +- Added `boost_by_distance`
3 - More flexible highlight options 4 - More flexible highlight options
4 5
5 ## 0.8.3 6 ## 0.8.3
@@ -616,16 +616,19 @@ Bounded by a box @@ -616,16 +616,19 @@ Bounded by a box
616 City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} 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 ```ruby 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 ## Inheritance 633 ## Inheritance
631 634
lib/searchkick/query.rb
@@ -209,39 +209,27 @@ module Searchkick @@ -209,39 +209,27 @@ module Searchkick
209 } 209 }
210 end 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 end 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 payload = { 228 payload = {
235 function_score: { 229 function_score: {
236 - functions: [  
237 - {  
238 - function => {  
239 - field => function_params  
240 - }  
241 - }  
242 - ], 230 + functions: custom_filters,
243 query: payload, 231 query: payload,
244 - score_mode: score_mode 232 + score_mode: "sum"
245 } 233 }
246 } 234 }
247 end 235 end
test/boost_test.rb
@@ -104,4 +104,13 @@ class TestBoost &lt; Minitest::Test @@ -104,4 +104,13 @@ class TestBoost &lt; Minitest::Test
104 assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}} 104 assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}}
105 end 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 end 116 end
test/sql_test.rb
@@ -261,15 +261,6 @@ class TestSql &lt; Minitest::Test @@ -261,15 +261,6 @@ class TestSql &lt; Minitest::Test
261 assert_search "product", ["Product"], where: {latitude: {gt: 99}} 261 assert_search "product", ["Product"], where: {latitude: {gt: 99}}
262 end 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 # load 264 # load
274 265
275 def test_load_default 266 def test_load_default