From afed3cd8148668fc0b76ef08bf15d3ccd7662311 Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Sun, 2 Nov 2014 19:41:04 -0800 Subject: [PATCH] Changed to boost_by_distance --- CHANGELOG.md | 1 + README.md | 13 ++++++++----- lib/searchkick/query.rb | 40 ++++++++++++++-------------------------- test/boost_test.rb | 9 +++++++++ test/sql_test.rb | 9 --------- 5 files changed, 32 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe032b..0f8a2c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 0.8.4 [unreleased] +- Added `boost_by_distance` - More flexible highlight options ## 0.8.3 diff --git a/README.md b/README.md index 25b48e5..47152bf 100644 --- a/README.md +++ b/README.md @@ -616,16 +616,19 @@ Bounded by a box City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} ``` -Modify search score by proximity to a point: +### Boost By Distance [master] + +Boost results by distance - closer results are boosted more ```ruby -City.search "san", proximity_factor: { field: :location, origin: [37, -122] } # field and origin mandatory -City.search "san", proximity_factor: { field: :location, origin: [37, -122], function: :linear, scale: "30mi", decay: 0.5 } # at 30mi, decrease score by 50% +City.search "san", boost_by_distance: {field: :location, origin: [37, -122]} ``` -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. +Also supports [additional options](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions) -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). +```ruby +City.search "san", boost_by_distance: {field: :location, origin: [37, -122], function: :linear, scale: "30mi", decay: 0.5} +``` ## Inheritance diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index 6ceb459..6c35e8c 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -209,39 +209,27 @@ module Searchkick } end - if custom_filters.any? - payload = { - function_score: { - functions: custom_filters, - query: payload, - score_mode: "sum" + boost_by_distance = options[:boost_by_distance] + if boost_by_distance + boost_by_distance = {function: :gauss, scale: "5mi"}.merge(boost_by_distance) + if !boost_by_distance[:field] or !boost_by_distance[:origin] + raise ArgumentError, "boost_by_distance requires :field and :origin" + end + function_params = boost_by_distance.select{|k,v| [:origin, :scale, :offset, :decay].include?(k) } + function_params[:origin] = function_params[:origin].reverse + custom_filters << { + boost_by_distance[:function] => { + boost_by_distance[:field] => function_params } } end - # Modify the query scoring by proximity to a geo point - if options[:proximity_factor] - proximity_factor = { function: :gauss, score_mode: :multiply, scale: "5mi" }.merge(options[:proximity_factor]) - (proximity_factor[:field] and proximity_factor[:origin]) or raise ArgumentError, "query() option :proximity_factor must contain at least :field and :origin" - - field = proximity_factor[:field] - function = proximity_factor[:function] - function_params = proximity_factor.select { |k,v| [:origin, :scale, :offset, :decay].include? k } - # Conform to GeoJSON convention of [longitude, latitude] - function_params[:origin] = function_params[:origin].reverse - score_mode = proximity_factor[:score_mode] - + if custom_filters.any? payload = { function_score: { - functions: [ - { - function => { - field => function_params - } - } - ], + functions: custom_filters, query: payload, - score_mode: score_mode + score_mode: "sum" } } end diff --git a/test/boost_test.rb b/test/boost_test.rb index bbf74f0..174cf55 100644 --- a/test/boost_test.rb +++ b/test/boost_test.rb @@ -104,4 +104,13 @@ class TestBoost < Minitest::Test assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}} end + def test_boost_by_distance + store [ + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}, + {name: "San Marino", latitude: 43.9333, longitude: 12.4667} + ] + assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {field: :location, origin: [37, -122], scale: "1000mi"} + end + end diff --git a/test/sql_test.rb b/test/sql_test.rb index 959d6d4..5efa699 100644 --- a/test/sql_test.rb +++ b/test/sql_test.rb @@ -261,15 +261,6 @@ class TestSql < Minitest::Test assert_search "product", ["Product"], where: {latitude: {gt: 99}} end - def test_proximity - store [ - {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, - {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}, - {name: "San Marino", latitude: 43.9333, longitude: 12.4667} - ] - assert_order "san", ["San Francisco", "San Antonio", "San Marino"], proximity_factor: {field: :location, origin: [37, -122]} - end - # load def test_load_default -- libgit2 0.21.0