Tengo un proyecto donde necesito construir un localizador de tiendas para un cliente.
Estoy usando un tipo de publicación personalizado " restaurant-location
" y he escrito el código para geocodificar las direcciones almacenadas en postmeta usando la API de Geocodificación de Google (aquí está el enlace que geocodifica la Casa Blanca de EE. UU. En JSON y he almacenado la latitud y la longitud de nuevo a campos personalizados.
He escrito una get_posts_by_geo_distance()
función que devuelve una lista de publicaciones en el orden de las más cercanas geográficamente utilizando la fórmula que encontré en la presentación de diapositivas en esta publicación . Puede llamar a mi función de esta manera (estoy comenzando con un lat / long "fuente" fijo):
include "wp-load.php";
$source_lat = 30.3935337;
$source_long = -86.4957833;
$results = get_posts_by_geo_distance(
'restaurant-location',
'geo_latitude',
'geo_longitude',
$source_lat,
$source_long);
echo '<ul>';
foreach($results as $post) {
$edit_url = get_edit_url($post->ID);
echo "<li>{$post->distance}: <a href=\"{$edit_url}\" target=\"_blank\">{$post->location}</a></li>";
}
echo '</ul>';
return;
Aquí está la función en get_posts_by_geo_distance()
sí:
function get_posts_by_geo_distance($post_type,$lat_key,$lng_key,$source_lat,$source_lng) {
global $wpdb;
$sql =<<<SQL
SELECT
rl.ID,
rl.post_title AS location,
ROUND(3956*2*ASIN(SQRT(POWER(SIN(({$source_lat}-abs(lat.lat))*pi()/180/2),2)+
COS({$source_lat}*pi()/180)*COS(abs(lat.lat)*pi()/180)*
POWER(SIN(({$source_lng}-lng.lng)*pi()/180/2),2))),3) AS distance
FROM
wp_posts rl
INNER JOIN (SELECT post_id,CAST(meta_value AS DECIMAL(11,7)) AS lat FROM wp_postmeta lat WHERE lat.meta_key='{$lat_key}') lat ON lat.post_id = rl.ID
INNER JOIN (SELECT post_id,CAST(meta_value AS DECIMAL(11,7)) AS lng FROM wp_postmeta lng WHERE lng.meta_key='{$lng_key}') lng ON lng.post_id = rl.ID
WHERE
rl.post_type='{$post_type}' AND rl.post_name<>'auto-draft'
ORDER BY
distance
SQL;
$sql = $wpdb->prepare($sql,$source_lat,$source_lat,$source_lng);
return $wpdb->get_results($sql);
}
Mi preocupación es que el SQL no está lo más optimizado posible. MySQL no puede ordenar por ningún índice disponible ya que el geo de origen es cambiante y no hay un conjunto finito de geos de origen para almacenar en caché. Actualmente estoy perplejo en cuanto a las formas de optimizarlo.
Teniendo en cuenta lo que ya he hecho, la pregunta es: ¿cómo harías para optimizar este caso de uso?
No es importante que guarde todo lo que he hecho si una mejor solución me obliga a tirarlo. Estoy abierto a considerar casi cualquier solución, excepto una que requiera hacer algo como instalar un servidor Sphinx o cualquier cosa que requiera una configuración MySQL personalizada. Básicamente, la solución debe poder funcionar en cualquier instalación simple de WordPress. (Dicho esto, sería genial si alguien quiere enumerar soluciones alternativas para otros que podrían ser más avanzados y para la posteridad).
Recursos encontrados
Para su información, investigué un poco sobre esto, así que en lugar de que haga la investigación nuevamente o que publique cualquiera de estos enlaces como respuesta, seguiré adelante y los incluiré.
- http://jebaird.com/blog/calculating-distance-miles-latitude-and-longitude
- http://wordpress.org/extend/plugins/geolocation/screenshots/
- http://code.google.com/apis/maps/articles/phpsqlsearch.html
- http://www.rooftopsolutions.nl/blog/229
- http://planet.mysql.com/entry/?id=18085
- http://blog.peoplesdns.com/archives/24
- http://www.petefreitag.com/item/622.cfm
- http://www.phpro.org/tutorials/Geo-Targetting-With-PHP-And-MySQL.html
- http://forum.geonames.org/gforum/posts/list/692.page
- http://forums.mysql.com/list.php?23
- http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
- http://developer.yahoo.com/maps/rest/V1/geocode.html
- http://geocoder.us/
Sobre la búsqueda de esfinges
- http://sphinxsearch.com/
- https://launchpad.net/wp-sphinx-plugin
- http://forums.site5.com/showthread.php?t=28981
- http://wordpress.org/extend/plugins/wordpress-sphinx-plugin/
- http://wordpress.org/extend/plugins/sphinx-search/
- http://www.mysqlperformanceblog.com/2008/02/15/mysql-performance-blog-now-uses-sphinx-for-site-search/
fuente
Esto podría ser demasiado tarde para usted, pero voy a responder de todos modos, con una respuesta similar a la que le di a esta pregunta relacionada , para que los futuros visitantes puedan consultar ambas preguntas.
No almacenaría estos valores en la tabla de metadatos de publicación, o al menos no solo allí. ¿Quieres una mesa con
post_id
,lat
,lon
columnas, por lo que puede colocar un índice delat, lon
consulta Y sobre eso. Esto no debería ser demasiado difícil de mantener actualizado con un enlace en guardar y actualizar la publicación.Cuando consulta la base de datos, define un cuadro delimitador alrededor del punto de partida, por lo que puede realizar una consulta eficiente para todos los
lat, lon
pares entre los bordes Norte-Sur y Este-Oeste del cuadro.Después de obtener este resultado reducido, puede hacer un cálculo de distancia más avanzado (direcciones de conducción reales o circulares) para filtrar las ubicaciones que se encuentran en las esquinas del cuadro delimitador y, por lo tanto, más lejos de lo que desea.
Aquí encontrará un ejemplo de código simple que funciona en el área de administración. Necesita crear la tabla de base de datos adicional usted mismo. El código está ordenado de más a menos interesante.
fuente
Llego tarde a la fiesta en este caso, pero mirando hacia atrás, este
get_post_meta
es realmente el problema aquí, en lugar de la consulta SQL que está utilizando.Recientemente tuve que hacer una búsqueda geográfica similar en un sitio que ejecuto, y en lugar de usar la metatabla para almacenar lat y lon (que requiere, en el mejor de los casos, dos uniones para buscar y, si está usando get_post_meta, dos bases de datos adicionales consultas por ubicación), creé una nueva tabla con un tipo de datos POINT de geometría espacialmente indexada.
Mi consulta se parecía mucho a la suya, con MySQL haciendo mucho trabajo pesado (omití las funciones trigonométricas y simplifiqué todo al espacio bidimensional, porque estaba lo suficientemente cerca para mis propósitos):
donde $ client_location es un valor devuelto por un servicio de búsqueda de IP de geo público (utilicé geoio.com, pero hay varios similares).
Puede parecer difícil de manejar, pero al probarlo, devolvió consistentemente las 5 ubicaciones más cercanas de una tabla de 80,000 filas en menos de .4 segundos.
Hasta que MySQL implemente la función DISTANCE que se propone, esta parece ser la mejor manera que encontré para implementar búsquedas de ubicación.
EDITAR: Agregar la estructura de la tabla para esta tabla en particular. Es un conjunto de listados de propiedades, por lo que puede o no ser similar a cualquier otro caso de uso.
La
geolocation
columna es lo único relevante para los propósitos aquí; consiste en coordenadas x (lon), y (lat) que solo busco desde la dirección al importar nuevos valores a la base de datos.fuente
Simplemente precalcule las distancias entre todas las entidades. Lo almacenaría en una tabla de base de datos propia, con la capacidad de indexar valores.
fuente