Ich habe ein Projekt, in dem ich einen Store Locator für einen Kunden erstellen muss.
Ich verwende einen benutzerdefinierten Beitragstyp " restaurant-location
" und habe den Code zum Geokodieren der in Postmeta gespeicherten Adressen mithilfe der Google Geocoding-API geschrieben (hier ist der Link, der das Weiße Haus der USA in JSON geokodiert, und ich habe den Breiten- und Längengrad zurückgespeichert zu benutzerdefinierten Feldern.
Ich habe eine get_posts_by_geo_distance()
Funktion geschrieben, die eine Liste von Beiträgen in der Reihenfolge derjenigen zurückgibt, die geografisch am nächsten sind, wobei die Formel verwendet wird, die ich in der Diashow in diesem Beitrag gefunden habe . Sie könnten meine Funktion so aufrufen (ich beginne mit einer festen "Quelle" 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;
Hier ist die Funktion get_posts_by_geo_distance()
selbst:
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);
}
Ich mache mir Sorgen, dass SQL so wenig wie möglich optimiert ist. MySQL kann nicht nach einem verfügbaren Index sortieren, da das Quell-Geo geändert werden kann und keine endliche Menge von Quell-Geos zwischengespeichert werden muss. Derzeit bin ich ratlos, wie ich es optimieren kann.
Unter Berücksichtigung dessen, was ich bereits getan habe, lautet die Frage: Wie würden Sie diesen Anwendungsfall optimieren?
Es ist nicht wichtig, dass ich alles behalte, was ich getan habe, wenn eine bessere Lösung mich dazu bringen würde, es wegzuwerfen. Ich bin offen für fast jede Lösung, außer für eine, bei der beispielsweise ein Sphinx-Server installiert werden muss oder für die eine angepasste MySQL-Konfiguration erforderlich ist. Grundsätzlich muss die Lösung in der Lage sein, mit jeder einfachen Vanille-WordPress-Installation zu arbeiten. (Das heißt, es wäre großartig, wenn jemand alternative Lösungen für andere auflisten möchte, die möglicherweise fortgeschrittener werden können, und für die Nachwelt.)
Ressourcen gefunden
Zu Ihrer Information, ich habe ein bisschen darüber recherchiert, anstatt dass Sie die Recherche erneut durchführen oder einen dieser Links als Antwort veröffentlichen, werde ich fortfahren und sie einschließen.
- 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/
In Bezug auf die Sphinx-Suche
- 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/
quelle
Dies mag für Sie zu spät sein, aber ich werde trotzdem mit einer ähnlichen Antwort antworten, die ich auf diese verwandte Frage gegeben habe , damit zukünftige Besucher auf beide Fragen verweisen können.
Ich würde diese Werte nicht in der Post-Metadatentabelle speichern oder zumindest nicht nur dort. Sie wollen eine Tabelle mit
post_id
,lat
,lon
Spalten, so können Sie einen Index setzenlat, lon
und Abfrage darauf. Dies sollte nicht zu schwierig sein, um mit einem Hook zum Speichern und Aktualisieren nach dem Start auf dem neuesten Stand zu bleiben.Wenn Sie die Datenbank abfragen, definieren Sie einen Begrenzungsrahmen um den Startpunkt, sodass Sie eine effiziente Abfrage für alle
lat, lon
Paare zwischen den Nord-Süd- und Ost-West-Grenzen des Rahmens durchführen können.Nachdem Sie dieses reduzierte Ergebnis erhalten haben, können Sie eine erweiterte Entfernungsberechnung (kreisförmige oder tatsächliche Fahrtrichtung) durchführen, um die Positionen herauszufiltern, die sich in den Ecken des Begrenzungsrahmens befinden und daher weiter entfernt sind, als Sie möchten.
Hier finden Sie ein einfaches Codebeispiel, das im Admin-Bereich funktioniert. Sie müssen die zusätzliche Datenbanktabelle selbst erstellen. Der Code ist von am wenigsten interessant geordnet.
quelle
Ich bin zu spät zur Party, aber wenn ich zurückblicke, die
get_post_meta
ist das hier wirklich das Problem und nicht die SQL-Abfrage, die Sie verwenden.Ich musste kürzlich eine ähnliche Geo-Suche auf einer von mir ausgeführten Site durchführen und nicht die Metatabelle zum Speichern von Lat und Lon verwenden (für die Suche sind höchstens zwei Joins erforderlich, und wenn Sie get_post_meta verwenden, zwei zusätzliche Datenbanken Abfragen pro Standort) habe ich eine neue Tabelle mit einem räumlich indizierten Geometrie-POINT-Datentyp erstellt.
Meine Anfrage sah Ihrer sehr ähnlich, wobei MySQL einen Großteil des schweren Hebens erledigte (ich habe die Triggerfunktionen weggelassen und alles auf den zweidimensionalen Raum vereinfacht, weil es für meine Zwecke nah genug war):
Dabei ist $ client_location ein Wert, der von einem öffentlichen Geo-IP-Suchdienst zurückgegeben wird (ich habe geoio.com verwendet, aber es gibt eine Reihe ähnlicher Werte).
Es mag unhandlich erscheinen, aber beim Testen wurden konsistent die nächsten 5 Positionen aus einer Tabelle mit 80.000 Zeilen in weniger als 0,4 Sekunden zurückgegeben.
Bis MySQL die vorgeschlagene DISTANCE-Funktion einführt, scheint dies der beste Weg zu sein, um Standortsuchen zu implementieren.
BEARBEITEN: Hinzufügen der Tabellenstruktur für diese bestimmte Tabelle. Es handelt sich um eine Reihe von Eigenschaftenlisten, sodass es möglicherweise keinem anderen Anwendungsfall ähnlich ist oder nicht.
Die
geolocation
Spalte ist das einzige, was für die Zwecke hier relevant ist; Es besteht aus x (lon), y (lat) Koordinaten, die ich beim Importieren neuer Werte in die Datenbank von der Adresse aus nachschaue.quelle
Berechnen Sie einfach die Abstände zwischen allen Entitäten vor. Ich würde das in einer eigenen Datenbanktabelle speichern, mit der Fähigkeit, Werte zu indizieren.
quelle