Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Revert "Revert "Include neighboring geohashes for proximity searches.""

This reverts commit 96068d8.
  • Loading branch information...
commit 9009aa2a5ec1b9a41bae4542ac7f880d1ee329bc 1 parent 96068d8
@outoftime authored
Showing with 60 additions and 6 deletions.
  1. +60 −6 sunspot/lib/sunspot/query/geo.rb
View
66 sunspot/lib/sunspot/query/geo.rb
@@ -8,7 +8,8 @@ module Sunspot
module Query
class Geo
MAX_PRECISION = 12
- DEFAULT_PRECISION = 7
+ NEIGHBOR_PRECISION = 7 # don't include neighbors above this precision
+ DEFAULT_PRECISION = 2
DEFAULT_PRECISION_FACTOR = 16.0
def initialize(field, lat, lng, options)
@@ -28,15 +29,34 @@ def to_subquery
def to_boolean_query
queries = []
+ geohashes = {}
+
+ # generate decreasingly-precise geohashes, with adjacent neighbors
MAX_PRECISION.downto(precision) do |i|
- star = i == MAX_PRECISION ? '' : '*'
- precision_boost = Util.format_float(
- boost * precision_factor ** (i-MAX_PRECISION).to_f, 3)
- queries << "#{@field.indexed_name}:#{@geohash[0, i]}#{star}^#{precision_boost}"
+ geohashes[i] = [@geohash[0, i]]
+ if i <= NEIGHBOR_PRECISION
+ neighbors = GeoHash.neighbors(@geohash[0, i + 1])
+ geohashes[i] = geohashes[i] + neighbors.reject{ |hash| hash[0, i] =~ %r{^@geohash[0, i]} }
+ end
+ end
+
+ # turn our geohashes into boosted query clauses
+ geohashes.keys.each do |p|
+ geohashes[p].each do |geohash|
+ star = p == MAX_PRECISION ? '' : '*'
+ pb = precision_boost(boost, precision_factor, p)
+ queries << "#{@field.indexed_name}:#{geohash}#{star}^#{pb}"
+ end
end
+
queries.join(' OR ')
end
-
+
+ def precision_boost(boost, precision_factor, precision)
+ f = boost * precision_factor ** (precision-MAX_PRECISION).to_f
+ Util.format_float(f, 3)
+ end
+
def precision
@options[:precision] || DEFAULT_PRECISION
end
@@ -51,3 +71,37 @@ def boost
end
end
end
+
+if __FILE__ == $0
+ require 'spec'
+ require File.join(File.dirname(__FILE__), "../../sunspot.rb")
+
+ describe "geo queries" do
+
+ before(:all) do
+ @mock_field = mock(
+ "test location field",
+ :indexed_name => "test_location_s"
+ )
+ end
+
+ it "should include neighbors in its boolean subquery" do
+ geo_query = Sunspot::Query::Geo.new(
+ @mock_field,
+ 32.7153292, -117.1572551,
+ :precision => 2
+ )
+ geo_query.to_subquery.scan(/test_location_s/).length.should == 23
+ end
+
+ # TODO: capture ordering assertions to avoid egregios regressions
+ # - generate a list of sample coordinates
+ # - pre-compute their distance from a specific search point
+ # - insert the documents into Solr
+ # - perform the search
+ # - assert a correct (rough) ordering
+
+ end
+
+ exit ::Spec::Runner::CommandLine.run
+end
Please sign in to comment.
Something went wrong with that request. Please try again.