Commit 7a1f2508a4ad72b9d6dc81376c9c21ade5e9719c

Authored by Andrew Kane
1 parent 515938a6

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

CHANGELOG.md
  1 +## 1.1.1 [unreleased]
  2 +
  3 +- Added support for `{lat: lat, lon: lon}` as preferred format for locations
  4 +
1 5 ## 1.1.0
2 6  
3 7 - Added `below` option to misspellings to improve performance
... ...
README.md
... ... @@ -779,7 +779,7 @@ class City < ActiveRecord::Base
779 779 searchkick locations: ["location"]
780 780  
781 781 def search_data
782   - attributes.merge location: [latitude, longitude]
  782 + attributes.merge location: {lat: latitude, lon: longitude}
783 783 end
784 784 end
785 785 ```
... ... @@ -787,13 +787,13 @@ end
787 787 Reindex and search with:
788 788  
789 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 793 Bounded by a box
794 794  
795 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 799 ### Boost By Distance
... ... @@ -801,13 +801,13 @@ City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -
801 801 Boost results by distance - closer results are boosted more
802 802  
803 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 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 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 813 ### Routing
... ...
lib/searchkick/index.rb
... ... @@ -568,10 +568,11 @@ module Searchkick
568 568 # locations
569 569 (options[:locations] || []).map(&:to_s).each do |field|
570 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 574 else
574   - source[field] = source[field].map(&:to_f).reverse
  575 + source[field] = location_value(source[field])
575 576 end
576 577 end
577 578 end
... ... @@ -581,6 +582,16 @@ module Searchkick
581 582 source.as_json
582 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 595 # change all BigDecimal values to floats due to
585 596 # https://github.com/rails/rails/issues/6033
586 597 # possible loss of precision :/
... ...
lib/searchkick/query.rb
... ... @@ -599,7 +599,7 @@ module Searchkick
599 599 when :near
600 600 filters << {
601 601 geo_distance: {
602   - field => op_value.map(&:to_f).reverse,
  602 + field => location_value(op_value),
603 603 distance: value[:within] || "50mi"
604 604 }
605 605 }
... ... @@ -607,8 +607,8 @@ module Searchkick
607 607 filters << {
608 608 geo_bounding_box: {
609 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 699 end
700 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 710 def below12?
703 711 below_version?("1.2.0")
704 712 end
... ...
test/test_helper.rb
... ... @@ -226,8 +226,8 @@ class Product
226 226 serializable_hash.except("id").merge(
227 227 conversions: conversions,
228 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 231 aisle: aisle
232 232 )
233 233 end
... ...
test/where_test.rb
... ... @@ -111,6 +111,14 @@ class WhereTest &lt; Minitest::Test
111 111 assert_search "san", ["San Francisco"], where: {location: {near: [37.5, -122.5]}}
112 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 122 def test_near_within
115 123 store [
116 124 {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
... ... @@ -120,6 +128,15 @@ class WhereTest &lt; Minitest::Test
120 128 assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}}
121 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 140 def test_top_left_bottom_right
124 141 store [
125 142 {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
... ... @@ -128,6 +145,14 @@ class WhereTest &lt; Minitest::Test
128 145 assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}}
129 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 156 def test_multiple_locations
132 157 store [
133 158 {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
... ... @@ -135,4 +160,12 @@ class WhereTest &lt; Minitest::Test
135 160 ]
136 161 assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}}
137 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 171 end
... ...