2

私はこれを達成する方法を理解するのに苦労しており、多くの人がこの質問をしても答えがないようです. 郵便番号を含む users テーブルがあります。米国のすべての郵便番号と緯度/経度を含む zips テーブルを作成しました。

私がやりたいことは、ユーザーが他のユーザーを検索できるように、2 つを接続することです。Thinking Sphinx を持っていますが、引き続き使用したいと考えています。検索する距離 (5、10、25、50、100、500 マイル) のチェックボックスをユーザーに提供したいと考えています。結果は常に最も近いユーザーを返す必要があります。

これにはコントローラーやモデルのコードは必要ないと思いますが、必要な場合はお問い合わせください。提供します。

検索フォーム:

<%= form_tag searches_path, method: :get do %>
<p>
        <%= text_field_tag :search, params[:search] %>
        <%= button_tag "Search", name: nil %>
        </p>
<% end %>

<P><%= link_to "Advanced Search", new_search_path %><p>

<%= form_tag users_path, method: :get do %>
<%= label :zip_code, "Enter zip code: " %>
<%= text_field_tag :zip_code, params[:zip_code] %>
<% end %>

/indices/user_index.rb:

     ThinkingSphinx::Index.define :user, :with => :active_record do
  # fields
  indexes name, :as => :user, :sortable => true
  indexes religion, zip_code, about_me, career, sexuality, children, user_smoke, user_drink, gender, ethnicity, education


  # attributes
  has id, created_at, updated_at
  has zips.city, :as => :zip_city

  has "RADIANS(zips.lat)",  :as => :latitude,  :type => :float
  has "RADIANS(zips.lon)", :as => :longitude, :type => :float


end

ユーザーモデル:

  has_and_belongs_to_many :zips

ジップモデル:

class Zip < ActiveRecord::Base
  attr_accessible :city, :lat, :lon, :code, :zipcode
  has_and_belongs_to_many :users

  validates :code, uniqueness: true

    self.primary_key = 'code'      

  def self.code(code)
    find_by(:code => code)
  end


end

ユーザー テーブルには次の列があります: zip_code.

郵便番号テーブルには次の列があります: codecitystatelatlon

4

4 に答える 4

1

最初のステップは、User とその Location の間の関連付けを作成して、Location の ActiveRecord を User の ActiveRecord から参照できるようにすることです。

class User < ActiveRecord::Base
  belongs_to :location
  attr_accessible :name
end

class Location < ActiveRecord::Base
  attr_accessible :city, :latitude, :longitude, :zipcode
end

次に、インデックスで関連付けを使用します。

ロケーション テーブルが確実に結合されるように、ロケーション モデルのフィールドのエイリアスを作成する必要があります。また、場所の緯度と経度の属性を追加する必要があります。

ThinkingSphinx::Index.define :user, :with => :active_record do
  # fields
  indexes name

  # attributes
  has created_at, updated_at
  has location.city, :as => :location_city
  has "RADIANS(locations.latitude)",  :as => :latitude,  :type => :float
  has "RADIANS(locations.longitude)", :as => :longitude, :type => :float

end

他の人がすでに述べたように、地球は平らではないため、場所間の距離を計算するときにそれを考慮する必要があります. そのためには、Haversine 関数が適しています。Thinking Sphinx にはそれが組み込まれており、 を使用してフィルタリングおよびソートできます:geo

次に、たとえば、緯度/経度パラメーターの 200 キロメートル以内にあるすべてのユーザーを度単位で検索するには、次のようにします。

class DistanceController < ApplicationController
  def search
    @lat = params[:lat].to_f * Math::PI / 180
    @lng = params[:lng].to_f * Math::PI / 180
    @users = User.search :geo => [@lat, @lng], :with => {:geodist => 0.0..200_000.0}, :order => "geodist ASC"
  end
end

デバッグのために、計算された距離もビューで参照できることを知っておくと便利です。

  <% @users.each do |user| %>
    <tr>
      <td><%= user.name %></td>
      <td><%= user.location.zipcode %></td>
      <td><%= user.location.city %></td>
      <td><%= user.distance %></td>
    </tr>

編集:完全を期すために、テーブル定義も追加するために、私の作業バージョンに関する詳細を追加しました。(db:migrate を使用して生成された MySQL。これらは、MySQL Workbench が生成する作成スクリプトです):

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `location_id` int(11) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `index_users_on_location_id` (`location_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


CREATE TABLE `locations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `zipcode` varchar(255) DEFAULT NULL,
  `latitude` float DEFAULT NULL,
  `longitude` float DEFAULT NULL,
  `city` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
于 2013-11-18T08:03:59.010 に答える
-1

Haversine 式を使用して、2 点間の距離を計算できます。

Landon Cox は、すでにこの場所で Haversine クラスを作成するのに苦労しました: http://www.esawdust.com/blog/gps/files/HaversineFormulaInRuby.html

以前のプロジェクトでこのクラスを使用しましたが、かなりうまく機能します

必要なのは、現在の場所または選択したユーザーからの各ユーザーの距離を比較するロジックを配置することだけです。すでにすべての緯度と経度を取得しているため、これは非常に簡単なはずです。

お役に立てれば。

于 2013-11-15T18:23:52.243 に答える