Commit 7a1f2508a4ad72b9d6dc81376c9c21ade5e9719c
1 parent
515938a6
Exists in
master
and in
21 other branches
Added support for {lat: lat, lon: lon} as preferred format for locations - #579
Showing
6 changed files
with
69 additions
and
13 deletions
Show diff stats
CHANGELOG.md
README.md
@@ -779,7 +779,7 @@ class City < ActiveRecord::Base | @@ -779,7 +779,7 @@ class City < ActiveRecord::Base | ||
779 | searchkick locations: ["location"] | 779 | searchkick locations: ["location"] |
780 | 780 | ||
781 | def search_data | 781 | def search_data |
782 | - attributes.merge location: [latitude, longitude] | 782 | + attributes.merge location: {lat: latitude, lon: longitude} |
783 | end | 783 | end |
784 | end | 784 | end |
785 | ``` | 785 | ``` |
@@ -787,13 +787,13 @@ end | @@ -787,13 +787,13 @@ end | ||
787 | Reindex and search with: | 787 | Reindex and search with: |
788 | 788 | ||
789 | ```ruby | 789 | ```ruby |
790 | -City.search "san", where: {location: {near: [37, -114], within: "100mi"}} # or 160km | 790 | +City.search "san", where: {location: {near: {lat: 37, lon: -114}, within: "100mi"}} # or 160km |
791 | ``` | 791 | ``` |
792 | 792 | ||
793 | Bounded by a box | 793 | Bounded by a box |
794 | 794 | ||
795 | ```ruby | 795 | ```ruby |
796 | -City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} | 796 | +City.search "san", where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}} |
797 | ``` | 797 | ``` |
798 | 798 | ||
799 | ### Boost By Distance | 799 | ### Boost By Distance |
@@ -801,13 +801,13 @@ City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, - | @@ -801,13 +801,13 @@ City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, - | ||
801 | Boost results by distance - closer results are boosted more | 801 | Boost results by distance - closer results are boosted more |
802 | 802 | ||
803 | ```ruby | 803 | ```ruby |
804 | -City.search "san", boost_by_distance: {field: :location, origin: [37, -122]} | 804 | +City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}} |
805 | ``` | 805 | ``` |
806 | 806 | ||
807 | Also supports [additional options](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions) | 807 | Also supports [additional options](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions) |
808 | 808 | ||
809 | ```ruby | 809 | ```ruby |
810 | -City.search "san", boost_by_distance: {field: :location, origin: [37, -122], function: :linear, scale: "30mi", decay: 0.5} | 810 | +City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}, function: :linear, scale: "30mi", decay: 0.5} |
811 | ``` | 811 | ``` |
812 | 812 | ||
813 | ### Routing | 813 | ### Routing |
lib/searchkick/index.rb
@@ -568,10 +568,11 @@ module Searchkick | @@ -568,10 +568,11 @@ module Searchkick | ||
568 | # locations | 568 | # locations |
569 | (options[:locations] || []).map(&:to_s).each do |field| | 569 | (options[:locations] || []).map(&:to_s).each do |field| |
570 | if source[field] | 570 | if source[field] |
571 | - if source[field].first.is_a?(Array) # array of arrays | ||
572 | - source[field] = source[field].map { |a| a.map(&:to_f).reverse } | 571 | + if !source[field].is_a?(Hash) && (source[field].first.is_a?(Array) || source[field].first.is_a?(Hash)) |
572 | + # multiple locations | ||
573 | + source[field] = source[field].map { |a| location_value(a) } | ||
573 | else | 574 | else |
574 | - source[field] = source[field].map(&:to_f).reverse | 575 | + source[field] = location_value(source[field]) |
575 | end | 576 | end |
576 | end | 577 | end |
577 | end | 578 | end |
@@ -581,6 +582,16 @@ module Searchkick | @@ -581,6 +582,16 @@ module Searchkick | ||
581 | source.as_json | 582 | source.as_json |
582 | end | 583 | end |
583 | 584 | ||
585 | + def location_value(value) | ||
586 | + if value.is_a?(Array) | ||
587 | + value.map(&:to_f).reverse | ||
588 | + elsif value.is_a?(Hash) | ||
589 | + {lat: value[:lat].to_f, lon: value[:lon].to_f} | ||
590 | + else | ||
591 | + value | ||
592 | + end | ||
593 | + end | ||
594 | + | ||
584 | # change all BigDecimal values to floats due to | 595 | # change all BigDecimal values to floats due to |
585 | # https://github.com/rails/rails/issues/6033 | 596 | # https://github.com/rails/rails/issues/6033 |
586 | # possible loss of precision :/ | 597 | # possible loss of precision :/ |
lib/searchkick/query.rb
@@ -599,7 +599,7 @@ module Searchkick | @@ -599,7 +599,7 @@ module Searchkick | ||
599 | when :near | 599 | when :near |
600 | filters << { | 600 | filters << { |
601 | geo_distance: { | 601 | geo_distance: { |
602 | - field => op_value.map(&:to_f).reverse, | 602 | + field => location_value(op_value), |
603 | distance: value[:within] || "50mi" | 603 | distance: value[:within] || "50mi" |
604 | } | 604 | } |
605 | } | 605 | } |
@@ -607,8 +607,8 @@ module Searchkick | @@ -607,8 +607,8 @@ module Searchkick | ||
607 | filters << { | 607 | filters << { |
608 | geo_bounding_box: { | 608 | geo_bounding_box: { |
609 | field => { | 609 | field => { |
610 | - top_left: op_value.map(&:to_f).reverse, | ||
611 | - bottom_right: value[:bottom_right].map(&:to_f).reverse | 610 | + top_left: location_value(op_value), |
611 | + bottom_right: location_value(value[:bottom_right]) | ||
612 | } | 612 | } |
613 | } | 613 | } |
614 | } | 614 | } |
@@ -699,6 +699,14 @@ module Searchkick | @@ -699,6 +699,14 @@ module Searchkick | ||
699 | end | 699 | end |
700 | end | 700 | end |
701 | 701 | ||
702 | + def location_value(value) | ||
703 | + if value.is_a?(Array) | ||
704 | + value.map(&:to_f).reverse | ||
705 | + else | ||
706 | + value | ||
707 | + end | ||
708 | + end | ||
709 | + | ||
702 | def below12? | 710 | def below12? |
703 | below_version?("1.2.0") | 711 | below_version?("1.2.0") |
704 | end | 712 | end |
test/test_helper.rb
@@ -226,8 +226,8 @@ class Product | @@ -226,8 +226,8 @@ class Product | ||
226 | serializable_hash.except("id").merge( | 226 | serializable_hash.except("id").merge( |
227 | conversions: conversions, | 227 | conversions: conversions, |
228 | user_ids: user_ids, | 228 | user_ids: user_ids, |
229 | - location: [latitude, longitude], | ||
230 | - multiple_locations: [[latitude, longitude], [0, 0]], | 229 | + location: {lat: latitude, lon: longitude}, |
230 | + multiple_locations: [{lat: latitude, lon: longitude}, {lat: 0, lon: 0}], | ||
231 | aisle: aisle | 231 | aisle: aisle |
232 | ) | 232 | ) |
233 | end | 233 | end |
test/where_test.rb
@@ -111,6 +111,14 @@ class WhereTest < Minitest::Test | @@ -111,6 +111,14 @@ class WhereTest < Minitest::Test | ||
111 | assert_search "san", ["San Francisco"], where: {location: {near: [37.5, -122.5]}} | 111 | assert_search "san", ["San Francisco"], where: {location: {near: [37.5, -122.5]}} |
112 | end | 112 | end |
113 | 113 | ||
114 | + def test_near_hash | ||
115 | + store [ | ||
116 | + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | ||
117 | + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} | ||
118 | + ] | ||
119 | + assert_search "san", ["San Francisco"], where: {location: {near: {lat: 37.5, lon: -122.5}}} | ||
120 | + end | ||
121 | + | ||
114 | def test_near_within | 122 | def test_near_within |
115 | store [ | 123 | store [ |
116 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | 124 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, |
@@ -120,6 +128,15 @@ class WhereTest < Minitest::Test | @@ -120,6 +128,15 @@ class WhereTest < Minitest::Test | ||
120 | assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}} | 128 | assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}} |
121 | end | 129 | end |
122 | 130 | ||
131 | + def test_near_within_hash | ||
132 | + store [ | ||
133 | + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | ||
134 | + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}, | ||
135 | + {name: "San Marino", latitude: 43.9333, longitude: 12.4667} | ||
136 | + ] | ||
137 | + assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: {lat: 37, lon: -122}, within: "2000mi"}} | ||
138 | + end | ||
139 | + | ||
123 | def test_top_left_bottom_right | 140 | def test_top_left_bottom_right |
124 | store [ | 141 | store [ |
125 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | 142 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, |
@@ -128,6 +145,14 @@ class WhereTest < Minitest::Test | @@ -128,6 +145,14 @@ class WhereTest < Minitest::Test | ||
128 | assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} | 145 | assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}} |
129 | end | 146 | end |
130 | 147 | ||
148 | + def test_top_left_bottom_right_hash | ||
149 | + store [ | ||
150 | + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | ||
151 | + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} | ||
152 | + ] | ||
153 | + assert_search "san", ["San Francisco"], where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}} | ||
154 | + end | ||
155 | + | ||
131 | def test_multiple_locations | 156 | def test_multiple_locations |
132 | store [ | 157 | store [ |
133 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | 158 | {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, |
@@ -135,4 +160,12 @@ class WhereTest < Minitest::Test | @@ -135,4 +160,12 @@ class WhereTest < Minitest::Test | ||
135 | ] | 160 | ] |
136 | assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}} | 161 | assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}} |
137 | end | 162 | end |
163 | + | ||
164 | + def test_multiple_locations_hash | ||
165 | + store [ | ||
166 | + {name: "San Francisco", latitude: 37.7833, longitude: -122.4167}, | ||
167 | + {name: "San Antonio", latitude: 29.4167, longitude: -98.5000} | ||
168 | + ] | ||
169 | + assert_search "san", ["San Francisco"], where: {multiple_locations: {near: {lat: 37.5, lon: -122.5}}} | ||
170 | + end | ||
138 | end | 171 | end |