Я использую GeoDjango с PostGIS. Тогда у меня возникают проблемы с тем, как получить ближайшую запись из данных координат из таблицы postgres db.
Как я могу запросить ближайшую запись в заданных координатах (широта и долгота типа строки)?
Ответ 1
Это ответ с использованием GeoDjango с PostGIS
Координаты точек должны быть объектом GEOSGeometry. Чтобы использовать его
from django.contrib.gis.geos import GEOSGeometry
point = GEOSGeometry('POINT(5 23)')
Тогда представьте, что у вас есть модель "Ресторан" и координаты точки. Итак, для ближайшего ресторана просто используйте:
Restaurants.objects.distance(point).order_by('distance')[0]
Ответ 2
В следующей версии PostGIS 2.0 появилась функция KNN gist, чтобы получить функции ближайшего соседа. Например:
SELECT ST_Distance(geom, 'SRID=26910;POINT(34.5 -23.2)'::geometry) AS d
FROM mypoints
ORDER BY geom <-> 'SRID=26910;POINT(34.5 -23.2)'::geometry LIMIT 1;
Эта функция находится в версии SVN, и вы можете ее протестировать/использовать сейчас.
Ответ 3
Я должен согласиться с ответом delawen, но сам по себе st_distance будет очень медленным. Чтобы ускорить работу, вам нужно использовать индексы GIST (обратите внимание на большую часть функции PostGIS, включая st_distance. НЕ используйте индексы: рекомендация по индексированию postgis).
Итак, сначала вы создадите буфер вокруг точки, а затем проверите его ограничивающий прямоугольник, используя "& &" (это использует встроенный индекс GIST, поэтому он будет работать намного лучше), а затем вы проверите расстояние "st_distance".
Например, чтобы получить ближайший "ресторан" из заданного местоположения (например, X = 1, Y = 1), вы должны написать:
select *,st_distance(the_geom_col,st_geomfromtext('POINT(1 1)',27700)) as distance
from restaurants where st_buffer(st_geomfromtext('POINT(1 1)',27700),100)
&& "the_geom_col"
Это будет очень быстро по сравнению с "st_distance", но результаты могут содержать рестораны, которые находятся на расстоянии более 100 метров от данного места (например, когда геометрия поддерживается в линейном или многоугольном форматах).
Чтобы получить более точные результаты, рестораны, которые находятся точно в диапазоне 100 метров, вы добавьте, следуя приведенному выше запросу:
and st_distance(the_geom_col,st_geomfromtext('POINTFROMTEXT(1 1)',27700)) <= 100
Это будет по-прежнему более эффективным и быстрым, чем использование st_distance самостоятельно. Поскольку база данных будет запускать st_distance только для записей, которые соответствуют первым критериям.
Итак, как правило, всякий раз, когда вам приходится выполнять дорогостоящие пространственные запросы, попробуйте:
- Отфильтруйте как можно больше ложных результатов, используя специальные операторы (см. специальные операции в официальные документы postgis.
- Затем напишите фактическую функцию проверки пространственных отношений.
- Всегда указывайте индекс GIST в столбце "geometry".
- Добавьте ограничивающие поля к вашим "геометриям", используя st_addbbox.
- Регулярно переиндексации и вакуумирования/анализа ваших таблиц.
Примечание. Размер буфера или фактическое расстояние должен быть в системе проецирования, которую вы используете, т.е. если вы используете EPSG: 4326 (Lat/Long), то вы даете эти расстояния в градусах. Например 1 метр в реальном мире = 0,00000899 градусов.. и 100 метров = делать математику:)
Ответ 4
У меня нет опыта работы с GeoDjango, но на PostgreSQL/PostGIS у вас есть функция st_distance (..). Итак, вы можете заказать свои результаты st_distance(geom_column, your_coordinates) asc
и посмотреть, какие ближайшие строки.
Если у вас есть простые координаты (без геометрии postgis), вы можете преобразовать ваши координаты в точку с помощью функции geometryFromText.
Это то, что вы искали? Если нет, попробуйте быть более явным.
Ответ 5
Пользователи PostgreSQL/PostGIS должны использовать оператор " ↔ " в предложении ORDER BY, чтобы получить "K ближайших соседей" (KNN), как сказано в Mike T в этот ответ.
Чтобы получить преимущества от улучшения производительности KNN-GiST в GeoDjango, вы можете написать следующее:
from django.contrib.gis.db.models.functions import GeomValue
from django.contrib.gis.geos import Point
from django.db.models.expressions import CombinedExpression, F
knn = 10
longitude = -96.876369
latitude = 29.905320
pnt = Point(longitude, latitude, srid=4326)
order_by_expression = CombinedExpression(F('geom'), '<->', GeomValue(pnt))
nearest_neighbors = Neighbor.objects.order_by(order_by_expression)[:knn]
Ответ 6
Использование PostGIS и GeoDjango для поиска ближайшего соседа
Рассмотрим эту модель:
from django.contrib.gis.geos import Point
from django.contrib.gis.db import models
class Store(models.Model):
name = models.CharField(max_length=100)
location = models.PointField(geography=True, srid=4326)
longitude = models.FloatField()
latitude = models.FloatField()
objects = models.GeoManager()
def save(self, **kwargs):
self.location = Point(self.longitude, self.latitude)
super(Store, self).save(**kwargs)
В представлении найдите все точки интереса в радиусе 100 миль от заданной долготы/широты:
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
point = Point(lng, lat)
points = Store.objects.filter(
location__distance_lte=(point, D(mi=100))
).distance(point).order_by('distance')
Показать результаты в шаблоне:
<ul>
{% for point in points %}
<li>{{ point.name }} is {{ point.distance.mi|floatformat }} miles away</li>
{% endfor %}
</ul>