Tagzania – Postgis – GeoDjango – Nearest Neighbours Distance (III)
Lunes, Marzo 23rd, 2009FASE 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.pointWHEN '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.pointWHEN '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.pointWHEN '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.