Skip to content
Snippets Groups Projects
Commit 33b89ff0 authored by Alex Reisner's avatar Alex Reisner
Browse files

Merge pull request #321 from mlandauer/bounding_box_2

Add bounding box optimisation
parents 660f4934 926467f1
No related branches found
No related tags found
No related merge requests found
......@@ -527,6 +527,15 @@ Calling `obj.coordinates` directly returns the internal representation of the co
For consistency with the rest of Geocoder, always use the `to_coordinates` method instead.
Optimisation of Distance Queries
--------------------------------
In MySQL and Postgres the finding of objects near a given point is speeded up by using a bounding box to limit the number of points over which a full distance calculation needs to be done.
To take advantage of this optimisation you need to add a composite index on latitude and longitude. In your Rails migration:
add_index :table, [:latitude, :longitude]
Distance Queries in SQLite
--------------------------
......
......@@ -102,15 +102,18 @@ module Geocoder::Store
options[:units] ||= (geocoder_options[:units] || Geocoder::Configuration.units)
bearing = bearing_sql(latitude, longitude, options)
distance = distance_sql(latitude, longitude, options)
b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
args = b + [
full_column_name(geocoder_options[:latitude]),
full_column_name(geocoder_options[:longitude])
]
bounding_box_conditions = Geocoder::Sql.within_bounding_box(*args)
if using_sqlite?
b = Geocoder::Calculations.bounding_box([latitude, longitude], radius, options)
args = b + [
full_column_name(geocoder_options[:latitude]),
full_column_name(geocoder_options[:longitude])
]
conditions = Geocoder::Sql.within_bounding_box(*args)
conditions = bounding_box_conditions
else
conditions = ["#{distance} <= ?", radius]
conditions = [bounding_box_conditions + " AND #{distance} <= ?", radius]
end
{
:select => select_clause(options[:select], distance, bearing),
......
require 'test_helper'
class NearTest < Test::Unit::TestCase
def test_near_scope_options_without_sqlite_includes_bounding_box_condition
result = Event.send(:near_scope_options, 1.0, 2.0, 5)
assert_match /test_table_name.latitude BETWEEN 0.9276\d* AND 1.0723\d* AND test_table_name.longitude BETWEEN 1.9276\d* AND 2.0723\d* AND /,
result[:conditions][0]
end
end
......@@ -4,6 +4,12 @@ require 'test/unit'
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
class MysqlConnection
def adapter_name
"mysql"
end
end
##
# Simulate enough of ActiveRecord::Base that objects can be used for testing.
#
......@@ -28,6 +34,10 @@ module ActiveRecord
def self.scope(*args); end
def self.connection
MysqlConnection.new
end
def method_missing(name, *args, &block)
if name.to_s[-1..-1] == "="
write_attribute name.to_s[0...-1], *args
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment