Lucene пространственная, точность - PullRequest
6 голосов
/ 12 июля 2011

Я следую примеру в "Lucene in Action", стр. 308-315, который описывает Lucene Spatial. Я использую Lucene 2.9.4. Я использовал http://geocoder.us/service/distance конечную точку, чтобы вычислить расстояние между некоторыми местоположениями, а затем написал модульные тесты, чтобы убедиться, что индекс может найти местоположения в пределах данного радиуса.

Мне интересно, насколько точной я могу ожидать, что люцен будет. Например, если я задаю радиус 10,0, а расстояние между точками широты и долготы составляет 9,99 мили, сможет ли оно найти это местоположение во всех случаях?

В связи с этим возникает вопрос, что я обнаружил, что поиск очень точен для малых значений радиуса (например, 10,0 или менее) и неточен для больших значений (например, r = 25,0).

Есть что-то, что я могу делать неправильно? Возможно ли, что искатель выберет уровень, который не имеет всех широт / длин для данного радиуса? Насколько я понимаю, он выбирает наименьший уровень, который гарантированно имеет все точки в радиусе, т. Е. Алгоритм уровня - это просто оптимизация.

EDIT: Также я нашел это: https://issues.apache.org/jira/browse/LUCENE-2519 и, по-видимому, фиксированный код здесь: http://code.google.com/p/spatial-search-lucene/source/browse/trunk/src/main/java/org/apache/lucene/spatial/tier/projection/SinusoidalProjector.java?r=38,, но когда я пропатчил свой код для использования фиксированного SinusoidalProjector, мой индекс возвращает ноль объявлений во всех случаях.

И это не вселяет в меня уверенности:

http://www.lucidimagination.com/blog/2010/07/20/update-spatial-search-in-apache-lucene-and-solr/

http://www.lucidimagination.com/search/document/c32e81783642df47/spatial_rethinking_cartesian_tiers_implementation#c32e81783642df47

Кажется, это указывает на то, что в коде существуют хаки, и простого исправления SinusoidalProjector недостаточно.

Ответы [ 2 ]

4 голосов
/ 13 июля 2011

Я потратил некоторое время на просмотр исходного кода и думаю, что понимаю, что происходит не так.Во-первых, я сделал неверное предположение, что расстояния, вычисленные с помощью geocoder.us, будут такими же, как и то, что lucene внутренне рассчитывает как расстояния между точками.Значения близки, но не точны.Поэтому я переключился на вычисление расстояний между парами широта / долгота, вызвав команду lucene

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 пространственный, находится на googlecode по адресу: http://code.google.com/p/spatial-search-lucene/,, и кажется, что реализация значительно изменилась, но я не слишком углублялся в детали.

0 голосов
/ 03 марта 2012

Они исправили это в Lucene 3.5.0.Большие расстояния теперь работают так же хорошо, как маленькие

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...