#java #database #geospatial
#java #База данных #геопространственный
Вопрос:
Предположим, у меня есть только этот API, предоставленный базой данных для выполнения геопространственного запроса, чтобы определить, какие записи / объекты в базе данных находятся вблизи определенной точки географического местоположения на заданном расстоянии.
EntityIterable entities = txn.find(entityType, propertyName, minValue, maxValue);
Где MinValue и MaxValue являются Java Comparable
. Тривиальный пример не-геопространственного использования для этого — для поиска, например, ценового диапазона:
EntityIterable entities = txn.find("Book", "price", 10.00, 20.00);
Который вернет все записи, цена 10.00
которых равна to 20.00
Теперь, если у меня есть GeoPoint
public class GeoPoint implements Comparable, Serializable {
private Double longitude;
private Double latitude;
}
И сохранение его в базе данных следующим образом:
Entity book = txn.createEntity("Book");
book.setProperty("price", 15.00)
book.setProperty("geoLocation, new GeoLocation(theLongitude, theLatitude));
И хотел бы запросить, как:
EntityIterable entities = txn.find("Book", "geoLocation", minGeo, maxGeo);
Очевидно, что этот запрос довольно линейный, и я понимаю, что причина, по которой работает пример с ценой книги, заключается в том, что Double
значение равно a Comparable
, поэтому запрос MIN-MAX сможет сравнивать price
значения s из всех объектов в базе данных с минимальным и максимальным значением, указанным в запросе.
Однако в случае геопространственного запроса все совсем по-другому. Мой вопрос в том, как мне создать класс GeoPoint как таковой, чтобы его можно было сравнить с использованием функции min max?
Есть ли способ взломать решение, чтобы иметь возможность линейно запрашивать географическое местоположение. Может быть, добавить некоторую жестко запрограммированную точку отсчета перед сохранением геопункта в базе данных?
Ответ №1:
Общий подход к этому — использовать некоторую кривую заполнения пространства, например кривую Гильберта. Кривая заполнения пространства отображает точку на плоскости 2D в точку на реальном интервале.
Библиотека Google S2 является адаптацией идеи для сферы и использует кривую Гильберта. Geohash использует Z-кривую для аналогичной идеи на 2D-карте.
Для поисковых запросов использование отдельных минимальных и максимальных значений не всегда оптимально, но обычно вы можете создать небольшой список интервалов и выполнить поиск по ним.
Комментарии:
1. Как вы можете запрашивать с помощью min-max при таком подходе?
2. По сути, вы строите круг с центром в вашей центральной точке и радиусе поиска и смотрите, какие интервалы кривой заполнения пространства пересекают этот круг. Это может быть один интервал или несколько из них. Получите минимальное / максимальное значение интервалов и выполните поиск точек внутри любого из интервалов. Вы можете использовать существующую библиотеку, такую как GeoHash или S2 от Google.
3. @michael-entil можете ли вы объяснить это в форме
EntityIterable entities = txn.find("Book", "geoLocation", min, max);
Я имею в виду, как предлагаемое вами решение вписывается в этот контекст?4. Проверьте ссылки, которые я добавил. Позиция на кривой логически описывается одним действительным числом (преобразуется в целое число в S2 или строку в GeoHash). Учитывая окружность на карте, вы будете знать минимальное / максимальное значение для позиции на кривой, где она пересекает этот круг, затем используйте эти минимальные / максимальные значения. Самый тривиальный (он не является точным — может пропустить точки, но все же широко используемый) запрос
GeoHash(location, precision) = GeoHash(center, precision)
.5. Итак, GeoHash может быть
java.util.Comparable
?