From 7a1f2508a4ad72b9d6dc81376c9c21ade5e9719c Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Mon, 14 Dec 2015 23:32:52 -0800 Subject: [PATCH] Added support for {lat: lat, lon: lon} as preferred format for locations - #579 --- CHANGELOG.md | 4 ++++ README.md | 10 +++++----- lib/searchkick/index.rb | 17 ++++++++++++++--- lib/searchkick/query.rb | 14 +++++++++++--- test/test_helper.rb | 4 ++-- test/where_test.rb | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a9cb20..b0ce5b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.1 [unreleased] + +- Added support for `{lat: lat, lon: lon}` as preferred format for locations + ## 1.1.0 - Added `below` option to misspellings to improve performance diff --git a/README.md b/README.md index e9a1760..cf07b92 100644 --- a/README.md +++ b/README.md @@ -779,7 +779,7 @@ class City < ActiveRecord::Base searchkick locations: ["location"] def search_data - attributes.merge location: [latitude, longitude] + attributes.merge location: {lat: latitude, lon: longitude} end end ``` @@ -787,13 +787,13 @@ end Reindex and search with: ```ruby -City.search "san", where: {location: {near: [37, -114], within: "100mi"}} # or 160km +City.search "san", where: {location: {near: {lat: 37, lon: -114}, within: "100mi"}} # or 160km ``` Bounded by a box ```ruby -City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} +City.search "san", where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}} ``` ### Boost By Distance @@ -801,13 +801,13 @@ City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, - Boost results by distance - closer results are boosted more ```ruby -City.search "san", boost_by_distance: {field: :location, origin: [37, -122]} +City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}} ``` Also supports [additional options](https://www.elastic.co/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} +City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}, function: :linear, scale: "30mi", decay: 0.5} ``` ### Routing diff --git a/lib/searchkick/index.rb b/lib/searchkick/index.rb index d583be3..795d306 100644 --- a/lib/searchkick/index.rb +++ b/lib/searchkick/index.rb @@ -568,10 +568,11 @@ module Searchkick # locations (options[:locations] || []).map(&:to_s).each do |field| if source[field] - if source[field].first.is_a?(Array) # array of arrays - source[field] = source[field].map { |a| a.map(&:to_f).reverse } + if !source[field].is_a?(Hash) && (source[field].first.is_a?(Array) || source[field].first.is_a?(Hash)) + # multiple locations + source[field] = source[field].map { |a| location_value(a) } else - source[field] = source[field].map(&:to_f).reverse + source[field] = location_value(source[field]) end end end @@ -581,6 +582,16 @@ module Searchkick source.as_json end + def location_value(value) + if value.is_a?(Array) + value.map(&:to_f).reverse + elsif value.is_a?(Hash) + {lat: value[:lat].to_f, lon: value[:lon].to_f} + else + value + end + end + # change all BigDecimal values to floats due to # https://github.com/rails/rails/issues/6033 # possible loss of precision :/ diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index b38e2a6..649297b 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -599,7 +599,7 @@ module Searchkick when :near filters << { geo_distance: { - field => op_value.map(&:to_f).reverse, + field => location_value(op_value), distance: value[:within] || "50mi" } } @@ -607,8 +607,8 @@ module Searchkick filters << { geo_bounding_box: { field => { - top_left: op_value.map(&:to_f).reverse, - bottom_right: value[:bottom_right].map(&:to_f).reverse + top_left: location_value(op_value), + bottom_right: location_value(value[:bottom_right]) } } } @@ -699,6 +699,14 @@ module Searchkick end end + def location_value(value) + if value.is_a?(Array) + value.map(&:to_f).reverse + else + value + end + end + def below12? below_version?("1.2.0") end diff --git a/test/test_helper.rb b/test/test_helper.rb index e06f483..3f12f24 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -226,8 +226,8 @@ class Product serializable_hash.except("id").merge( conversions: conversions, user_ids: user_ids, - location: [latitude, longitude], - multiple_locations: [[latitude, longitude], [0, 0]], + location: {lat: latitude, lon: longitude}, + multiple_locations: [{lat: latitude, lon: longitude}, {lat: 0, lon: 0}], aisle: aisle ) end diff --git a/test/where_test.rb b/test/where_test.rb index d6dfc35..21d6814 100644 --- a/test/where_test.rb +++ b/test/where_test.rb @@ -111,6 +111,14 @@ class WhereTest < Minitest::Test assert_search "san", ["San Francisco"], where: {location: {near: [37.5, -122.5]}} end + def test_near_hash + store [ + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} + ] + assert_search "san", ["San Francisco"], where: {location: {near: {lat: 37.5, lon: -122.5}}} + end + def test_near_within store [ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, @@ -120,6 +128,15 @@ class WhereTest < Minitest::Test assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}} end + def test_near_within_hash + 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_search "san", ["San Francisco", "San Antonio"], where: {location: {near: {lat: 37, lon: -122}, within: "2000mi"}} + end + def test_top_left_bottom_right store [ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, @@ -128,6 +145,14 @@ class WhereTest < Minitest::Test assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} end + def test_top_left_bottom_right_hash + store [ + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} + ] + assert_search "san", ["San Francisco"], where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}} + end + def test_multiple_locations store [ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, @@ -135,4 +160,12 @@ class WhereTest < Minitest::Test ] assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}} end + + def test_multiple_locations_hash + store [ + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} + ] + assert_search "san", ["San Francisco"], where: {multiple_locations: {near: {lat: 37.5, lon: -122.5}}} + end end -- libgit2 0.21.0