Mam projekt, w którym muszę zbudować lokalizator sklepu dla klienta.
Używam niestandardowego typu posta „ restaurant-location
” i napisałem kod do geokodowania adresów przechowywanych w postmeta za pomocą Google Geocoding API (tutaj link, który geokoduje amerykański Biały Dom w JSON, a ja zapisałem szerokość i długość geograficzną z powrotem do pól niestandardowych.
Napisałem get_posts_by_geo_distance()
funkcję, która zwraca listę postów w kolejności tych najbliższych geograficznie, korzystając ze wzoru znalezionego w pokazie slajdów w tym poście . Możesz tak wywołać moją funkcję (zaczynam od stałego „źródła” 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;
Oto get_posts_by_geo_distance()
sama funkcja :
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);
}
Obawiam się, że SQL jest tak niezoptymalizowany, jak to tylko możliwe. MySQL nie może uporządkować według żadnego dostępnego indeksu, ponieważ geo źródłowe jest zmienne i nie ma skończonego zestawu geo źródłowych do buforowania. Obecnie mam problemy z optymalizacją.
Biorąc pod uwagę to, co już zrobiłem, pytanie brzmi: jak poszedłbyś na optymalizację tego przypadku użycia?
Nie jest ważne, aby zachować wszystko, co zrobiłem, jeśli lepsze rozwiązanie pozwoliłoby mi to wyrzucić. Jestem otwarty na rozważenie prawie każdego rozwiązania, z wyjątkiem takiego, które wymaga zrobienia czegoś takiego jak instalacja serwera Sphinx lub czegokolwiek, co wymaga spersonalizowanej konfiguracji MySQL. Zasadniczo rozwiązanie musi działać na dowolnej zwykłej waniliowej instalacji WordPress. (To powiedziawszy, byłoby wspaniale, gdyby ktokolwiek chciał wymienić alternatywne rozwiązania dla innych, którzy mogliby być bardziej zaawansowani i dla potomnych.)
Znaleziono zasoby
Do Twojej wiadomości, przeprowadziłem trochę badań na ten temat, więc zamiast tego czy robisz to ponownie, czy raczej zamiast publikować którekolwiek z tych linków jako odpowiedź, dodam je.
- 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-w--MySQL
- http://developer.yahoo.com/maps/rest/V1/geocode.html
- http://geocoder.us/
Odnośnie wyszukiwania Sfinksa
- 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/
źródło
To może być dla ciebie za późno, ale i tak odpowiem, udzielając podobnej odpowiedzi, jak udzieliłem na to powiązane pytanie , aby przyszli odwiedzający mogli odnieść się do obu pytań.
Nie zapisałbym tych wartości w tabeli metadanych posta, a przynajmniej nie tylko tam. Chcesz stół z
post_id
,lat
,lon
kolumny, dzięki czemu można złożyć indekslat, lon
i zapytania w tej sprawie. To nie powinno być zbyt trudne, aby być na bieżąco z hakiem na zapisywanie i aktualizowanie postów.Podczas wyszukiwania w bazie danych definiuje się ramkę graniczną wokół punktu początkowego, dzięki czemu można wykonać wydajne zapytanie dla wszystkich
lat, lon
par między granicami północ-południe i wschód-zachód ramki.Po uzyskaniu tego zmniejszonego wyniku możesz wykonać bardziej zaawansowane obliczanie odległości (okrągłe lub rzeczywiste wskazówki dojazdu), aby odfiltrować lokalizacje znajdujące się w rogach ramki ograniczającej i dalej, niż chcesz.
Tutaj znajdziesz prosty przykład kodu, który działa w obszarze administratora. Musisz samodzielnie utworzyć dodatkową tabelę bazy danych. Kod jest uporządkowany od najbardziej do najmniej interesującego.
źródło
Spóźniam się na przyjęcie w tej sprawie, ale patrząc wstecz,
get_post_meta
to naprawdę jest tutaj problem, a nie zapytanie SQL, którego używasz.Niedawno musiałem przeprowadzić podobne wyszukiwanie geograficzne na stronie, którą prowadzę, i zamiast używać tabeli meta do przechowywania lat i lon (co wymaga co najmniej dwóch sprzężeń, aby wyszukać, a jeśli używasz get_post_meta, dwóch dodatkowych baz danych zapytań na lokalizację), utworzyłem nową tabelę z typem danych przestrzennie indeksowanej geometrii POINT.
Moje zapytanie wyglądało podobnie do twojego, z MySQL wykonującym wiele ciężkich operacji podnoszenia (pominąłem funkcje triggera i uprościłem wszystko do dwuwymiarowej przestrzeni, ponieważ było wystarczająco blisko do moich celów):
gdzie $ lokalizacja_klienta jest wartością zwracaną przez publiczną usługę wyszukiwania geograficznego adresu IP (korzystałem z geoio.com, ale istnieje wiele podobnych).
Może się to wydawać niewygodne, ale podczas jego testowania konsekwentnie zwracał najbliższe 5 lokalizacji ze 80 000-wierszowego stołu w czasie poniżej 0,4 sekundy.
Dopóki MySQL nie uruchomi proponowanej funkcji ODLEGŁOŚĆ, wydaje się to najlepszym sposobem na wdrożenie wyszukiwania lokalizacji.
EDYCJA: Dodanie struktury tabeli dla tej konkretnej tabeli. Jest to zestaw list właściwości, więc może, ale nie musi, być podobny do jakiegokolwiek innego przypadku użycia.
geolocation
Kolumna jest jedyną rzeczą, istotne dla tutejszych celów; składa się ze współrzędnych x (lon), y (lat), które po prostu szukam z adresu po zaimportowaniu nowych wartości do bazy danych.źródło
Wystarczy wstępnie obliczyć odległości między wszystkimi jednostkami. Chciałbym zapisać to w tabeli bazy danych, z możliwością indeksowania wartości.
źródło