У меня есть проект, в котором мне нужно создать локатор магазина для клиента.
Я использую пользовательский тип записи " restaurant-location
", и я написал код для геокодирования адресов, хранящихся в postmeta, с помощью API геокодирования Google (вот ссылка, которая геокодирует Белый дом США в JSON, и я сохранил широту и долготу обратно в настраиваемые поля.
Я написал get_posts_by_geo_distance()
функцию, которая возвращает список постов в порядке тех, которые географически ближе всего, используя формулу, которую я нашел в слайд-шоу в этом посте . Вы можете вызвать мою функцию следующим образом (я начинаю с фиксированного «исходного» значения 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;
Вот сама функция get_posts_by_geo_distance()
:
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);
}
Меня беспокоит то, что SQL-код настолько неоптимизирован, насколько это возможно. MySQL не может упорядочить по любому доступному индексу, так как исходный гео изменчив и нет ограниченного набора исходных гео, чтобы кешировать. В настоящее время я озадачен тем, как оптимизировать его.
Принимая во внимание то, что я уже сделал, вопрос: как бы вы пошли на оптимизацию этого варианта использования?
Не важно, чтобы я сохранил все, что сделал, если бы лучшее решение заставило меня его выбросить. Я открыт для рассмотрения практически любого решения, кроме одного, которое требует чего-то вроде установки сервера Sphinx или чего-либо, что требует настраиваемой конфигурации MySQL. По сути, решение должно работать на любой простой установке WordPress. (Тем не менее, было бы здорово, если бы кто-нибудь захотел перечислить альтернативные решения для тех, кто мог бы стать более продвинутым и для потомков.)
Ресурсы найдены
К вашему сведению, я провел небольшое исследование по этому вопросу, поэтому вместо того, чтобы вы провели исследование снова или вместо того, чтобы вы разместили какие-либо из этих ссылок в качестве ответа, я продолжу и включу их.
- 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/
Что касается поиска сфинкса
- 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/
источник
Это может быть слишком поздно для вас, но я все равно отвечу тем же ответом, что и на этот связанный вопрос , поэтому будущие посетители могут обратиться к обоим вопросам.
Я не буду хранить эти значения в таблице метаданных поста или, по крайней мере, не только там. Вы хотите , чтобы таблица с
post_id
,lat
,lon
колонны, так что вы можете поместить индексlat, lon
и запрос по этому поводу . Это не должно быть слишком сложно, чтобы идти в ногу со временем с крючком после сохранения и обновления.Когда вы запрашиваете базу данных, вы определяете ограничивающий прямоугольник вокруг начальной точки, чтобы вы могли выполнить эффективный запрос для всех
lat, lon
пар между границами север-юг и восток-запад этого прямоугольника.После того, как вы получите этот уменьшенный результат, вы можете выполнить более сложный (круговой или фактический маршрут движения) расчет расстояния, чтобы отфильтровать места, которые находятся в углах ограничительной рамки и, следовательно, дальше, чем вы хотите.
Здесь вы найдете простой пример кода, который работает в области администратора. Вам нужно создать дополнительную таблицу базы данных самостоятельно. Код упорядочен от самых до наименее интересных.
источник
Я опаздываю на вечеринку по этому вопросу, но, оглядываясь назад, на
get_post_meta
самом деле проблема здесь, а не в SQL-запросе, который вы используете.Недавно мне пришлось выполнить аналогичный гео-поиск на сайте, который я запускаю, и вместо того, чтобы использовать мета-таблицу для хранения значений lat и lon (для этого требуется в лучшем случае два соединения для поиска и, если вы используете get_post_meta, две дополнительные базы данных запросов на местоположение), я создал новую таблицу с пространственно индексируемой геометрией типа данных POINT.
Мой запрос выглядел очень похоже на ваш, поскольку MySQL выполнял большую часть тяжелой работы (я оставил функции триггера и упростил все до двумерного пространства, потому что он был достаточно близок для моих целей):
где $ client_location - это значение, возвращаемое общедоступной службой поиска географических IP-адресов (я использовал geoio.com, но есть ряд похожих).
Это может показаться громоздким, но при тестировании он последовательно возвращал ближайшие 5 местоположений из таблицы с 80000 строками за менее чем 0,4 секунды.
До тех пор, пока MySQL не развернет предлагаемую функцию DISTANCE, это кажется лучшим способом, который я нашел для реализации поиска местоположения.
РЕДАКТИРОВАТЬ: Добавление структуры таблицы для этой конкретной таблицы. Это набор списков свойств, так что он может или не может быть похож на любой другой вариант использования.
geolocation
Столбец единственным значения для целей здесь; он состоит из координат x (lon), y (lat), которые я просто смотрю с адреса при импорте новых значений в базу данных.источник
Просто предварительно рассчитайте расстояния между всеми объектами. Я бы сохранил это в таблице базы данных самостоятельно, с возможностью индексирования значений.
источник