One of the neat features of Sphinx is the ability to sort and filter by a calculated geographical distance, from latitude and longitude values. It’s quite easy to get set up, as well.
Setting up the Indexes
Firstly, you’ll need to be storing latitude and longitude values as attributes for each relevant document. So, in your index definition, you’ll need something like this, if you’ve already got the columns in your model:
Keep in mind, though, that Sphinx needs these values to be floats, and tracking positions by radians instead of degrees. If this isn’t the case in your own database (which isn’t a surprise - most people store the values as degrees), then you’ll need to manually convert columns for the attributes:
Once this is done, you’ll need to rebuild your Sphinx indexes:
You can name your attributes to be whatever you like - Thinking Sphinx will automatically use them if they’re called latitude, longitude, lat or lng.
Once your indexes are set up, then you can begin searching. You need to make sure you’re doing two things:
- Provide a geographical reference point
- Filter or sort by the calculated distance
For the first, you can provide an array of two arguments (latitude and longitude, again in radians) to the
:geo option. For the second, you’ll need to refer to Sphinx’s generated attribute
geodist in a filter and/or a sort argument.
If you do not provide any reference to
geodist, then the lat/lng values will be ignored by Sphinx.
Note: Sphinx expects the latitude and longitude values to be in radians - so you will probably need to convert the values when searching.
Thinking Sphinx v1/v2
Note: If you are using an older version of Thinking Sphinx, then the generated geodist attribute needs to be referenced with an @ prefix:
Thinking Sphinx since 3.0.0
When you provide a
:geo option to your search, the distance pane is automatically added to search results, and so you can access the calculated Sphinx distance through either the
geodist methods (your model’s own methods of those names take precedence if they exist):
It’s worth noting that the distance is in metres - so those stuck on the Imperial system (Americans, that’s you), you might want to convert to less archaic measurements.
Thinking Sphinx before 3.0.0
There’s two ways to access the calculated distance. You can either enumerate through the collection using
Or, you can access the distance as part of the @sphinx_attributes@ collection: