Google Places API とGeocoderで最も近いコンビニまでの距離を計算する
今回は、Google Places APIを使用してWebアプリケーションを作ることがあったので、その時の知見をログとして残します。
今回実施したこと
住所・地域・建物を検索した時に、その検索結果の場所から一番近いコンビニの情報を持ってくる。そして、そのコンビニまでの距離を計算する。GoogleのAPIはJavaScriptで書かれているため、どうやってRubyで計算するかと考えた時に、Geocoderなるものを見つけたので使用してみた。
処理の内容
コンビニの情報に指定して情報を取得する方法。APIからjson形式で情報をとってくる際に、URIに「types」属性を指定する。このtypesではコンビニ(convenience_store)や病院(hospital)などを指定することができる。属性の一覧については、以下のURLに記載されている。
プレイスタイプ | Google Places API | Google Developers
APIで取得した結果は距離順にソートされているわけではないので、さらに「rankby=distance」を指定することで距離順にソートされた状態で情報を取得できる。
SampleCode
緯度・経度の計算はGeocoderを使用して求めている。しかし、コンビニの緯度・経度はAPIから取得した情報から格納している。その二つの情報をGeocoder::Calculations.distance_betweenメソッドに引数として渡すことで二点間の距離を求めている。
require 'net/https' require 'uri' require 'json' require 'geocoder' API_KEY = 'YOUR_API_KEY' SEARCH_KEY = '六本木' types = 'convenience_store' language = 'ja' #Geocoderの設定 Geocoder.configure(language: :ja, units: :km) #formから入力した場所の住所 address = Geocoder.address(SEARCH_KEY) #緯度・経度の情報 lat = Geocoder.search(SEARCH_KEY)[0].geometry['location'].values[0] lng = Geocoder.search(SEARCH_KEY)[0].geometry['location'].values[1] place_ll = Geocoder.search(SEARCH_KEY)[0].geometry['location'].values.join(',') #検索のためのURI uri = URI.parse "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=#{lat},#{lng}&types=#{types}&sensor=false&rankby=distance&language=ja&key=#{API_KEY}" request = Net::HTTP::Get.new(uri.request_uri) response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| http.request(request) end #jsonをresultsに格納 body = JSON.parse(response.body) results = body['results'] results.each_with_index do |place, idx| location = place['geometry']['location'] lat, lng = location['lat'], location['lng'] #自分が入力した住所と、その近辺にあるコンビニとの距離を求めている。(kmなので、四捨五入と1000掛けでmに変更する) distance = Geocoder::Calculations.distance_between(place_ll,"#{lat},#{lng}").round(3)*1000 p "#{idx+1}: #{place['name']}: #{distance}m " end
Result
概ね間違っていないが、「5」と「6」に逆転現象が起きている。実際にGoogleMAPで調べてみると確かに6の方が遠くになっている。これは、Geocoderの距離の計算の仕方がGoogleの計算方法と異なるため起きていると思われる。もしGoogleのAPIで二点間の距離を求めたい場合はGoogle Maps Directions API にて求めることができる。
"1: セブンイレブン 六本木七丁目店: 59.0m " "2: ファミリーマート六本木七丁目店: 129.0m " "3: セブン−イレブンセントラム六本木店: 134.0m " "4: ローソン 六本木七丁目店: 190.0m " "5: ミニストップ 六本木四丁目店: 216.0m " "6: ファミリーマート 六本木通り店: 205.0m " "7: セブンイレブン 東京ミッドタウン店: 223.0m " "8: ファミリーマート・赤坂九丁目店: 250.0m " "9: ローソン メトロス六本木店: 251.0m " "10: ファミリーマート六本木ヒルズ店: 262.0m " "11: ファミリーマート六本木ミッドタウン店: 249.0m " "12: デイリーヤマザキ 六本木交差点店: 286.0m " "13: ナチュラルローソン 乃木坂店: 298.0m " "14: ファミリーマート 六本木交差点南店: 307.0m " "15: ローソン EXタワープラス店: 306.0m " "16: ファミリーマート六本木駅前店: 331.0m " "17: ナチュラルローソン 六本木ヒルズ店: 407.0m " "18: セブン−イレブン 六本木5丁目店: 420.0m " "19: セブンイレブン 西麻布3丁目六本木通り店: 446.0m " "20: ファミリーマート 六本木六丁目店: 409.0m "