Rails
MySQL
Elasticsearch
GIS
PostGIS

WIP@Railsで地理座標を計算してソート

More than 1 year has passed since last update.

目的

自分のGPS座標と、ある地点の距離郡を計算し、近い順からソートしたい。そこで、いくつかの選択肢を調べてみました。もし、何かご存知ならアドバイスをお願いできませんでしょうか🙇

PostGIS

何が違うのか? PostGISと最新版MySQLの GIS機能を徹底比較によるとMySQLとPostGIS共にGPS座標を計算できるようだ。

開発環境

HomebrewでPostGISをインストール、利用するまで

本番環境

Amazon RDS for PostgreSQLによると、AWSはPostGISに対応している。- PostGIS: Using Geospatial Data with Rails and Django Apps によるとHerokuでも使えそうです。

参考情報

MySQL

https://kenpg.bitbucket.org/blog/201511/29/slides20151127_rev.pdf によると出来そうで、今回の要件を満たしそうで直ぐに判断できなかったので、後回しとしました。

MySQL5.7のgeometry型を使えば使えるのではという情報を頂きました。geometry型は5.6でも使えるのですが、インデックスが貼れるのは5.7.4LABからのようです。

[Rails]Railsのバージョンを上げたことでspatial_adapterが使用できなくなりましたを参考に、activerecord-mysql2spatial-adapterを使ってみましたが、なんだかうまく行かずでした。

2年ほど、activerecord-mysql2spatial-adapterも更新が無く、mysql geometry railsなどのクエリで検索してみましたが、あまり情報がヒットせず、gem周りで解決したりするのは、この問題に対してはメジャーな方法ではないのかなと思いました。

そのため、MySQLのコードを発行するプログラムを作成して、この問題に取り組もうと思います。

例えば、このようなマイグレーションを書いてもrake db:migrateは可能です。

db/migrate/20170208125740_add_latlong_to_shops.rb
class AddLatlongToShops < ActiveRecord::Migration[5.0]
  def change
    add_column :shops, :latlong, :geometry
  end
end

ただ、db/scheme.rbがうまく作成できなくなってしまいます。

db/schema.rb
# Could not dump table "shops" because of following StandardError
#   Unknown type 'geometry' for column 'latlong'

ですので、Could not dump table “data” because of following StandardErrorなどを参考にdb/scheme.rbをやめてdb/structure.sqlを生成するようにしましょう。

db/structure.sql
--
-- Table structure for table `shops`
--

CREATE TABLE `shops` (
  ...
  `latlong` geometry DEFAULT NULL
  ...
)

MongoDB

MongoDBのGeospatialを使えば出来るかも。

参考情報

ElasticSearch

Elasticsearchに空間データを突っ込む

SQLで距離を計算する

緯度・経度を用いて距離を算出するSQLが参考になりそう。ただ、件数が増えると実行時間が気になります。10000件程度では問題にはならないようでした。

GeocorderでRailsアプリで簡単に位置情報を扱う はとても便利なgemです。alexreisner/geocoder/lib/geocoder/sql.rb によると上記と同様にSQLで実行しているようです。

geocodedには既知のバグとして pluckやincludesが正常に動作しない場合があるようです。

geocodedのSQLはかなり工夫されていて、素早く動作するように設計されているように感じました。

少し運用してみましたが、実際にデータが増えてくるとレスポンス速度が厳しい感じでした。特に近い距離の中に、結構多めの座標が固まってしまい、工夫しているフィルタ部分を抜けて、結構計算が働いてしまうせいかもしれません。

距離計算?クラウド

軽く見た感じだと、直ぐには見つけられ無さそうだった。