Eu tenho um projeto em que preciso construir um localizador de lojas para um cliente.
Estou usando um tipo de postagem personalizado " restaurant-location
" e escrevi o código para geocodificar os endereços armazenados no postmeta usando a API de geocodificação do Google (aqui está o link que codifica geograficamente a Casa Branca dos EUA em JSON e a latitude e a longitude de volta para campos personalizados.
Eu escrevi uma get_posts_by_geo_distance()
função que retorna uma lista de postagens na ordem daquelas mais próximas geograficamente, usando a fórmula que encontrei na apresentação de slides deste post . Você pode chamar minha função assim (estou começando com uma "fonte" fixa 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;
Aqui está a get_posts_by_geo_distance()
própria função :
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);
}
Minha preocupação é que o SQL seja o mais otimizado possível. O MySQL não pode ordenar por nenhum índice disponível, pois a localização geográfica da fonte é mutável e não há um conjunto finito de áreas geográficas de origem a serem armazenadas em cache. Atualmente, estou perplexo quanto às maneiras de otimizá-lo.
Levando em consideração o que já fiz, a pergunta é: como você otimizaria esse caso de uso?
Não é importante manter tudo o que fiz se uma solução melhor me permitir jogar fora. Estou aberto a considerar quase qualquer solução exceto uma que exige algo como instalar um servidor Sphinx ou qualquer coisa que exija uma configuração personalizada do MySQL. Basicamente, a solução precisa funcionar em qualquer instalação simples do WordPress. (Dito isto, seria ótimo se alguém quisesse listar soluções alternativas para outras pessoas que possam ser mais avançadas e posteriores.)
Recursos Encontrados
Para sua informação, eu pesquisei um pouco sobre isso, em vez de você fazer a pesquisa novamente ou em vez de postar qualquer um desses links como resposta. Vou adiante e incluí-los.
- 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/
Em relação à pesquisa Sphinx
- 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/
fonte
Pode ser tarde demais para você, mas vou responder de qualquer maneira, com uma resposta semelhante à que dei a essa pergunta relacionada , para que futuros visitantes possam consultar as duas perguntas.
Eu não armazenaria esses valores na tabela de metadados de postagem, ou pelo menos não apenas lá. Você quer uma tabela com
post_id
,lat
,lon
colunas, então você pode colocar um índice delat, lon
e consulta sobre isso. Não deve ser muito difícil manter-se atualizado com um gancho após salvar e atualizar.Ao consultar o banco de dados, você define uma caixa delimitadora em torno do ponto inicial, para poder fazer uma consulta eficiente para todos os
lat, lon
pares entre as bordas norte-sul e leste-oeste da caixa.Depois de obter esse resultado reduzido, é possível fazer um cálculo de distância mais avançado (direções de direção circulares ou reais) para filtrar os locais que estão nos cantos da caixa delimitadora e, portanto, mais longe do que você deseja.
Aqui você encontra um exemplo de código simples que funciona na área de administração. Você precisa criar a tabela extra de banco de dados. O código é ordenado do mais para o menos interessante.
fonte
Estou atrasado para a festa, mas olhando para trás, esse
get_post_meta
é realmente o problema aqui, em vez da consulta SQL que você está usando.Recentemente, tive que fazer uma pesquisa geográfica semelhante em um site que eu corro e, em vez de usar a tabela meta para armazenar lat e lon (o que exige, no máximo, duas junções para procurar e, se você estiver usando get_post_meta, dois bancos de dados adicionais consultas por local), criei uma nova tabela com um tipo de dados POINT de geometria indexada espacialmente.
Minha consulta se parecia muito com a sua, com o MySQL fazendo muito trabalho pesado (deixei de fora as funções trigonométricas e simplifiquei tudo para o espaço bidimensional, porque estava próximo o suficiente para meus propósitos):
em que $ client_location é um valor retornado por um serviço público de pesquisa geográfica por IP (usei geoio.com, mas existem vários similares).
Pode parecer complicado, mas ao testá-lo, ele sempre retornou os 5 locais mais próximos de uma tabela de 80.000 linhas em menos de 0,4 segundos.
Até o MySQL lançar a função DISTANCE que está sendo proposta, esta parece ser a melhor maneira que eu encontrei para implementar pesquisas de localização.
Edição: Adicionando a estrutura da tabela para esta tabela específica. É um conjunto de listagens de propriedades, portanto pode ou não ser semelhante a qualquer outro caso de uso.
A
geolocation
coluna é a única coisa relevante para os propósitos aqui; consiste nas coordenadas x (lon), y (lat) que apenas procuro pelo endereço ao importar novos valores no banco de dados.fonte
Apenas pré-calcule as distâncias entre todas as entidades. Eu armazenaria isso em uma tabela de banco de dados por conta própria, com a capacidade de indexar valores.
fonte