我花了一些时间查看源代码,我想我明白出了什么问题。首先,我做了一个错误的假设,即 geocoder.us 计算的距离与 lucene 内部计算的点之间的距离相同。这些值很接近,但并不准确。所以我转而通过调用 lucene's 来计算纬度/经度对之间的距离
double distance = DistanceUtils.getInstance().getDistanceMi(lat1,lon1,lat2,lon2);
接下来我研究了DistanceQueryBuilder 类http://grepcode.com/file/repo1.maven.org/maven2/org.apache.lucene/lucene-spatial/2.9.4/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java?av=f,我认为它有一个错误。
它计算边界框以获取笛卡尔层,如下所示:
CartesianPolyFilterBuilder cpf = new CartesianPolyFilterBuilder(tierFieldPrefix);
Filter cartesianFilter = cpf.getBoundingArea(lat, lng, miles);
通过查看 LLRect.createBox http://grepcode.com/file/repo1.maven.org/maven2/org.apache.lucene/lucene-spatial/2.9.4/org/apache/lucene/spatial/geometry/shape/LLRect.java#LLRect.createBox%28org.apache.lucene.spatial.geometry.LatLng%2Cdouble%2Cdouble%29 很清楚,getBoudningArea 的第三个参数将被视为边界框的完整宽度/高度。所以传递半径值会导致边界框太小。
解决方法是提供一个替代版本的 DistanceQueryBuilder 来执行此操作:
Filter cartesianFilter = cpf.getBoundingArea(lat,lng,miles*2);
这似乎有效。我仍然相信 DistanceApproximation http://grepcode.com/file/repo1.maven.org/maven2/org.apache.lucene/lucene-spatial/2.9.4/org/apache/lucene/spatial/geometry/shape/DistanceApproximation.java#DistanceApproximation.getMilesPerLngDeg%28double%29 被破坏了,因为似乎以下操作应该是可逆的,但它们不是:
// similar to implementation of DistanceUtils.getBoundary():
double milesPerLng = DistanceApproximation.getMilesPerLngDeg(lat);
double milesPerLat = DistanceApproximation.getMilesperLatDeg();
double lngDelta = radius / milesPerLng;
double latDelta = radius / milesPerLat;
// Now it seems like this should be roughly true:
assertEquals(radius, DistanceUtils.getInstance().getDistanceMi(lat,lng,lat,lng+lngDelta));
assertEquals(radius, DistanceUtils.getInstance().getDistanceMi(lat,lng,lat+latDelta,lng));
但事实并非如此。例如,当上面的代码给出 lat=34、lng=-118 和 radius=25(而不是断言我只是打印结果)时,我得到:
Lng delta: 0.36142327178505024, dist: 20.725929003138496
Lat delta: 0.4359569489852007, dist: 30.155567734407825
我猜测代码之所以有效,是因为在选择边界框后选择的笛卡尔层将导致区域比边界框大一些。但我认为这不会得到保证。
我希望对此有更多了解的人可以发表评论,因为这些只是在研究代码一个下午后的观察。我确实注意到 lucene spatial 的最新代码位于 googlecode 上:http://code.google.com/p/spatial-search-lucene/,并且实现似乎发生了重大变化,但我没有深入挖掘细节。