<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>opensoul.org - Location-based search with Sphinx and acts_as_geocodable Changes</title>
  <id>tag:opensoul.org,2009:/2009/4/15/location-based-search-with-sphinx-and-acts_as_geocodable/changes</id>
  <generator version="0.8.0" uri="http://mephistoblog.com">Mephisto Drax</generator>
  <link href="http://opensoul.org/2009/4/15/location-based-search-with-sphinx-and-acts_as_geocodable/changes.xml" rel="self" type="application/atom+xml"/>
  <link href="/2009/4/15/location-based-search-with-sphinx-and-acts_as_geocodable" rel="alternate" type="text/html"/>
  <updated>2009-04-15T00:40:53Z</updated>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2009-04-15:530:1</id>
    <updated>2009-04-15T00:40:53Z</updated>
    <link href="http://opensoul.org/2009/9/5/location-based-search-with-sphinx-and-acts_as_geocodable" rel="alternate" type="text/html"/>
    <title>Location-based search with Sphinx and acts_as_geocodable</title>
<content type="html">&lt;p&gt;&lt;a href=&quot;http://www.sphinxsearch.com/&quot;&gt;Sphinx&lt;/a&gt;, everybody&#8217;s favorite search engine, has support for location-based search, giving you geo-aware full-text searching. So now you can find all of the garage sales on Saturday within 20 miles that have LPs and a lawn mower.&lt;/p&gt;


	&lt;p&gt;All you need to do is add latitude and longitude (in radians) to the index, allowing you can limit the results to records within a distance of a point. The hardest part is getting the coordinates, but &lt;a href=&quot;http://github.com/collectiveidea/acts_as_geocodable&quot;&gt;acts_as_geocodable&lt;/a&gt; makes that really easy.&lt;/p&gt;


	&lt;p&gt;To start, install &lt;a href=&quot;http://github.com/collectiveidea/acts_as_geocodable&quot;&gt;acts_as_geocodable&lt;/a&gt;. Once you have that configured properly, install &lt;a href=&quot;http://ts.freelancing-gods.com/&quot;&gt;ThinkingSphinx&lt;/a&gt; and define an index on your geocodable model and add the coordinates to the index:&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;class Listing &amp;lt; ActiveRecord::Base
  acts_as_geocodable

  define_index do
    indexes title
    indexes description

    has geocoding.geocode(:id), :as =&amp;gt; :geocode_id
    has 'RADIANS(geocodes.latitude)', :as =&amp;gt; :latitude, :type =&amp;gt; :float
    has 'RADIANS(geocodes.longitude)', :as =&amp;gt; :longitude, :type =&amp;gt; :float
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The three lines that start with &lt;code&gt;has&lt;/code&gt; add the geocode id, and the latitude and longitude in radians to the index. Our index doesn&#8217;t need the geocode id, but we have to add it so that ThinkingSphinx properly joins the geocodes table.&lt;/p&gt;


	&lt;p&gt;After you rebuild the index and start the daemon, you can search for records by location. Here&#8217;s an example of taking a zip code from a user and finding all records with in 20 miles.&lt;/p&gt;


&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;def search
  location = Geocode.geocoder.locate(params[:zip]).coordinates.map(&amp;amp;:to_radians)
  @listings = Listing.search(params[:q], :geo =&amp;gt; location, :with =&amp;gt; {'@geodist' =&amp;gt; 0.0..(20 * 1610.0)})
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;First we look up the coordinates of the zip code that the user entered. Then we do a search with the &lt;code&gt;:geo&lt;/code&gt; parameter, limiting the results using the special &lt;code&gt;@geodist&lt;/code&gt; condition. We have to pass in a range of floats that represent the distance of the points in meters
(and since the US is in the stone age, I&#8217;m converting from miles).&lt;/p&gt;</content>  </entry>
</feed>
