php - Búsqueda de proximidad
mysql proximity (3)
¿Cómo realiza una aplicación una búsqueda de proximidad? Por ejemplo, un usuario escribe un código postal, luego la aplicación enumera todas las empresas dentro de las 20 millas ordenadas por proximidad.
Quiero construir algo así en PHP y MySQL. ¿Es este enfoque correcto?
- Obtener las direcciones de las ubicaciones que me interesan y almacenarlas en mi base de datos
- Geocodifica todas las direcciones con el servicio de geocodificación de Google
- Escriba una consulta de base de datos que incluya la fórmula de Haversine para hacer la búsqueda de proximidad y ordenar
¿Esta bien? En el paso 3, voy a calcular la proximidad para cada consulta. ¿Es mejor tener una tabla de PROXIMIDAD que enumere la distancia entre cada negocio y algunas ubicaciones de referencia?
Si hay suficientes registros para que la velocidad sea importante, esta es una forma de indexarlos con anticipación.
Defina una cuadrícula de contenedores alrededor de 20 millas en un lado. Almacene el número de contenedor con el registro de cada tienda. En el momento de la búsqueda, calcule los números de todos los contenedores que se cruzan en un radio de 20 millas desde su punto de búsqueda. Luego recupere todas las tiendas en cualquiera de esos contenedores y proceda como antes.
Hacemos esto para alrededor de 1200 ubicaciones. Simplemente usaría la fórmula Haversine sobre la marcha, aunque dependiendo de su aplicación, podría ser mejor almacenarla en PHP en lugar de SQL. (Nuestra implementación está en .net por lo que su kilometraje puede variar).
Realmente, nuestro mayor inconveniente con la forma en que lo implementamos, es que cada cálculo (hasta hace poco) tenía que calcularse en el nivel de datos, que era extremadamente lento (cuando digo lento, realmente me refiero a no instantáneo tardé aproximadamente un segundo). ), pero eso se debió al hecho de que tenía que calcular la distancia para las 1200 ubicaciones en función del código postal suministrado.
Dependiendo de la ruta que elijas, hay formas de acelerar los cálculos de la distancia numérica, mirando la longitud y la latitud y quitando las que están fuera de un rango predefinido (por ejemplo, si estás mirando todas las direcciones dentro de las 20 millas hay una en el rango de longitud, puede calcular qué direcciones deben caer a 20 millas de distancia). Eso puede acelerar su consulta si es necesario.
De hecho, buscamos almacenar todas las combinaciones posibles en nuestra base de datos. En realidad, parece que podría ser una gran tienda de datos, pero en realidad no está en el gran alcance de las cosas. Con los índices puede ser bastante rápido, y no tiene que preocuparse por la optimización del algoritmo, etc. Decidimos no hacerlo, porque teníamos la ecuación en C # y nos permitía almacenar en caché la información necesaria para hacer todos los cálculos en el nivel de negocios O bien funcionará bien, es solo una cuestión de cuál es tu preferencia.
Usamos esto para hacer muchos miles de puntos. Es importante si está realizando esto en SQL para tener un índice en la columna Latitud y Longitud. Intentamos hacer esto en SQL 2008 con índices espaciales, pero realmente no vimos el aumento de rendimiento que esperábamos. Sin embargo, si desea calcular dentro de una cierta distancia de un ZIP, debe pensar si va a usar el centroide ZIP o una representación poligonal del código postal.
Haversine Forumla es un buen lugar para comenzar.
No hemos tenido problemas de rendimiento al calcular la distancia sobre la marcha, lo calculamos con anticipación para algunas aplicaciones donde conocemos los puntos con anticipación y habrá millones de registros.
SELECT
[DistanceRadius]=
69.09 *
DEGREES(
ACOS(
SIN( RADIANS(latitude) )*SIN( RADIANS(@ziplat) )
+
COS( RADIANS(latitude) )*COS( RADIANS(@ziplat) )
*
COS( RADIANS(longitude - (@ziplon)) )
)
)
,*
FROM
table
) sub
WHERE
sub.DistanceRadius < @radius