J'ai un projet où j'ai besoin de construire un localisateur de magasin pour un client.
J'utilise un type de publication personnalisé " restaurant-location
" et j'ai écrit le code pour géocoder les adresses stockées dans postmeta à l'aide de l' API Google Geocoding (voici le lien qui géocode la US White House en JSON et j'ai stocké la latitude et la longitude en arrière aux champs personnalisés.
J'ai écrit une get_posts_by_geo_distance()
fonction qui renvoie une liste de messages dans l'ordre de ceux qui sont les plus proches géographiquement en utilisant la formule que j'ai trouvée dans le diaporama de ce message . Vous pourriez appeler ma fonction comme ça (je commence avec une "source" fixe lat / long):
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;
Voici la fonction get_posts_by_geo_distance()
elle-même:
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);
}
Ma préoccupation est que le SQL n'est pas aussi optimisé que possible. MySQL ne peut pas trier par aucun index disponible car la géo source est modifiable et il n'y a pas un ensemble fini de géos source à mettre en cache. Actuellement, je suis perplexe quant aux moyens de l'optimiser.
En tenant compte de ce que j'ai déjà fait, la question est: comment feriez-vous pour optimiser ce cas d'utilisation?
Ce n'est pas important que je garde tout ce que j'ai fait si une meilleure solution m'oblige à le jeter. Je suis ouvert à envisager presque toutes les solutions, à l' exception de celle qui nécessite de faire quelque chose comme l'installation d'un serveur Sphinx ou tout ce qui nécessite une configuration MySQL personnalisée. Fondamentalement, la solution doit pouvoir fonctionner sur n'importe quelle installation WordPress ordinaire. (Cela dit, ce serait formidable si quelqu'un voulait énumérer des solutions alternatives pour d'autres qui pourraient être plus avancés et pour la postérité.)
Ressources trouvées
Pour info, j'ai fait un peu de recherche à ce sujet, donc plutôt que de faire à nouveau la recherche ou plutôt que de poster l'un de ces liens comme réponse, je vais aller de l'avant et les inclure.
- 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/
Concernant Sphinx Search
- 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/
la source
C'est peut-être trop tard pour vous, mais je vais quand même répondre, avec une réponse similaire à celle que j'ai donnée à cette question connexe , afin que les futurs visiteurs puissent se référer aux deux questions.
Je ne stockerais pas ces valeurs dans la table des métadonnées post, ou du moins pas seulement là-bas. Vous voulez une table avec
post_id
,lat
,lon
colonnes, vous pouvez donc placer un indexlat, lon
et d' interrogation sur ce point . Cela ne devrait pas être trop difficile à maintenir à jour avec un crochet sur la sauvegarde et la mise à jour des publications.Lorsque vous interrogez la base de données, vous définissez un cadre de délimitation autour du point de départ, afin de pouvoir effectuer une requête efficace pour toutes les
lat, lon
paires entre les bordures Nord-Sud et Est-Ouest du cadre.Après avoir obtenu ce résultat réduit, vous pouvez effectuer un calcul de distance plus avancé (directions circulaires ou réelles) pour filtrer les emplacements qui se trouvent dans les coins de la zone de délimitation et donc plus loin que vous le souhaitez.
Vous trouverez ici un exemple de code simple qui fonctionne dans la zone d'administration. Vous devez créer vous-même la table de base de données supplémentaire. Le code est ordonné du plus intéressant au moins intéressant.
la source
Je suis en retard à la fête sur celui-ci, mais en y repensant,
get_post_meta
c'est vraiment le problème ici, plutôt que la requête SQL que vous utilisez.J'ai récemment dû faire une recherche géographique similaire sur un site que j'exécute, et plutôt que d'utiliser la méta-table pour stocker lat et lon (ce qui nécessite au mieux deux jointures pour rechercher et, si vous utilisez get_post_meta, deux bases de données supplémentaires requêtes par emplacement), j'ai créé une nouvelle table avec un type de données POINT de géométrie indexée spatialement.
Ma requête ressemblait beaucoup à la vôtre, MySQL effectuant une grande partie du travail lourd (j'ai laissé de côté les fonctions trigonométriques et j'ai tout simplifié en un espace à deux dimensions, car il était suffisamment proche pour mes besoins):
où $ client_location est une valeur renvoyée par un service de recherche IP géo public (j'ai utilisé geoio.com, mais il y en a plusieurs similaires).
Cela peut sembler compliqué, mais en le testant, il a systématiquement renvoyé les 5 emplacements les plus proches d'une table de 80 000 lignes en moins de 0,4 sec.
Jusqu'à ce que MySQL déploie la fonction DISTANCE qui est proposée, cela semble être le meilleur moyen que j'ai trouvé pour implémenter les recherches d'emplacement.
EDIT: Ajout de la structure de table pour cette table particulière. C'est un ensemble de listes de propriétés, il peut donc être similaire ou non à tout autre cas d'utilisation.
La
geolocation
colonne est la seule chose pertinente aux fins ici; il se compose de coordonnées x (lon), y (lat) que je viens de rechercher à partir de l'adresse lors de l'importation de nouvelles valeurs dans la base de données.la source
Pré-calculez simplement les distances entre toutes les entités. Je stockerais cela dans une table de base de données seule, avec la possibilité d'indexer des valeurs.
la source