Commit 7a1f2508a4ad72b9d6dc81376c9c21ade5e9719c

Authored by Andrew Kane
1 parent 515938a6

Added support for {lat: lat, lon: lon} as preferred format for locations - #579

  1 +## 1.1.1 [unreleased]
  2 +
  3 +- Added support for `{lat: lat, lon: lon}` as preferred format for locations
  4 +
1 ## 1.1.0 5 ## 1.1.0
2 6
3 - Added `below` option to misspellings to improve performance 7 - Added `below` option to misspellings to improve performance
@@ -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 &lt; Minitest::Test @@ -111,6 +111,14 @@ class WhereTest &lt; 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 &lt; Minitest::Test @@ -120,6 +128,15 @@ class WhereTest &lt; 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 &lt; Minitest::Test @@ -128,6 +145,14 @@ class WhereTest &lt; 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 &lt; Minitest::Test @@ -135,4 +160,12 @@ class WhereTest &lt; 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