Commit afed3cd8148668fc0b76ef08bf15d3ccd7662311

Authored by Andrew Kane
1 parent 5a19d5ad

Changed to boost_by_distance

CHANGELOG.md
1 1 ## 0.8.4 [unreleased]
2 2  
  3 +- Added `boost_by_distance`
3 4 - More flexible highlight options
4 5  
5 6 ## 0.8.3
... ...
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 &lt; 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 &lt; 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
... ...