Tagzania – Postgis – GeoDjango – Nearest Neighbours Distance (III)

FASE 2: Problema & Solución

Los cálculos de distancia en linea y poligonos seguían siendo costosos para nuestro servidor.

Por lo que utilizamos el siguiente criterio (postgis), para que todas las busquedas fueran lo más rápidas posibles: de punto a punto.

– Un punto no tiene problema alguno.

– Una linea ==> ST_StartPoint(line)

– Un poligono ==> ST_Centroid(polygon)

** Funciones Postgis – ya que en Geodjango no existe el startpoint de lineas.

Así:

SELECT a.* FROM items AS a WHERE a.id != %s
ORDER BY (
CASE WHEN a.item_type='POINT' THEN ST_Distance(
(SELECT CASE b.item_type WHEN 'POINT' THEN b.point
WHEN 'POLYLINE' THEN ST_StartPoint(b.geometry)
ELSE ST_Centroid(b.geometry)END FROM items AS b WHERE b.id= %s), a.point)
WHEN a.item_type='POLYLINE' THEN ST_Distance(
(SELECT CASE c.item_type WHEN 'POINT' THEN c.point
WHEN 'POLYLINE' THEN ST_StartPoint(b.geometry)
ELSE ST_Centroid(b.geometry)END FROM items AS c WHERE c.id= %s), ST_StartPoint(a.geometry)
WHEN a.item_type='POLYGON' THEN ST_Distance(
(SELECT CASE c.item_type WHEN 'POINT' THEN c.point
WHEN 'POLYLINE' THEN ST_StartPoint(b.geometry)
ELSE ST_Centroid(b.geometry)END FROM items AS c WHERE c.id= %s), ST_Centroid(a.geometry)
) END) LIMIT %s;

Pero el precálculo de StartPoint y Centroid por cada vez que se acceda a esta consulta seguía siendo costoso para el sistema.

Solución: Tomamos la decisión de crear un punto central (center_point) por cada elemento (POI), y así facilitar la operación de cálculo de distancias.

center_point = models.PointField(blank=True, null = True)
POINT =>> center_point = self.point
LINE =>> center_point = fromstr('POINT(' + line_coords[0]+ ')')
POLYGON =>> center_point = self.polygon.centroid

Con lo que ademas conseguiamos que geodjango aplicase directamente su función de distancia:

tzp = get_object_or_404(items, id = ***)

near_items = Items.objects.distance(tzp.center_point).order_by(’distance’)

RESUMIENDO:

Cada vez que insertemos una geometría, debemos realizar estos precálculos para que las consultas sean más agiles a la hora de buscar los puntos mas cercanos a este que estamos insertando.

1.- Simplificar tanto lineas(polyline) como los poligonos(polygon). SIMPLIFY()

2.- Crear un punto central por cada geometría. (center_point)

De esta manera conseguimos que la busqueda sea más ágil, aunque después, estas geometrías sean muy complicadas en cuanto a cantidad de intersecciones, … pero esto ya pasa a manos del navegador.

¡Nuestro servidor respira!

Tags: , , , ,

Leave a Reply