Como melhor implementar a pesquisa de vizinhos mais próximos no mysql?

10

Então, resumindo,

  1. Qual deve ser o tipo de dados de latitude e longitude?
  2. Qual comando SQL devo chamar para obter os primeiros 100 restaurantes mais próximos, por exemplo?

Detalhe:

Tenho 100k biz gravar cada um com latitude e longitude. Vejo que o MySQL realmente suporta um tipo de dados chamado point. Devo usar isso em vez disso?

O MySQL suporta o sistema de armazenamento KDTree http://en.wikipedia.org/wiki/File:KDTree-animation.gif

É melhor usar o tipo de dados de ponto em vez do tipo de dados flutuante regular para armazenar latitutude e longitude?

Eventualmente, quero encontrar coisas como os 100 primeiros restaurantes mais próximos dos pontos 105,6, por exemplo, e meus bancos de dados contêm muitos negócios e pontos. Obviamente, calcular a distância uma a uma para todos os registros e para todos os pontos seria O (n) e, portanto, é uma merda.

Observe que estou ciente de uma solução mais simples descrita em Como aplicativos como o Yelp recupera informações de distância do banco de dados de forma eficiente e implementará isso também para começar. Essa é uma boa resposta.

No entanto, acho que há um creme da resposta da colheita que deve superar esse certo? De fato, armazenar localizações com base em latitude e longitude e encontrar objetos mais próximos é um problema muito comum, espero que o mysql tenha um padrão de design especial para isso. Isso tem?

Onde posso aprender mais sobre isso? Obrigado.

user4951
fonte
Você já viu essa pergunta ?
Jack diz que tente topanswers.xyz
Parece que a solução aqui dba.stackexchange.com/questions/4210/… é a melhor solução. Quero dizer, existe uma coisa chamada espacial MYSQL. No entanto, você não pode extrair coisas como onde (distância (x) <20). Ainda não está implementado.
user4951

Respostas:

11

Quanto aos padrões de design, a pergunta do Yelp é bastante comum.

Para uma resposta mais complexa, você provavelmente precisará da distância geoespacial. Aqui está um ponto de vista fascinante sobre esse tópico (e aqui também uma versão em pdf). No entanto, a matemática envolvida é bastante feia.

No slide:

set @orig_lat=122.4058; set @orig_lon=37.7907;
set @dist=10;

SELECT *, 3956 * 2 * ASIN(SQRT(
POWER(SIN((@orig_lat - abs(dest.lat)) * pi()/180 / 2), 2) +  COS(@orig_lat * pi()/180 ) * COS(abs(dest.lat) * pi()/180) *  POWER(SIN((@orig_lon  dest.lon) * pi()/180 / 2), 2) )) as  distance
FROM hotels dest 
having distance < @dist
ORDER BY distance limit 10

Há uma resposta mais longa e aprofundada sobre a distância geoespacial no Stack Overflow .

Mas você ainda deseja limitar os resultados por latitude e longitude.

Por fim, evitaria o tipo de dados POINT e seguia com latitude / longitude. No momento, não há como determinar a distância entre dois pontos, então você precisará armazenar a latitude / longitude para esse cálculo de qualquer maneira.

Um último link: você também pode verificar este segmento de SO referente à aceleração das consultas usando índices espaciais.

Richard
fonte
[ERRO na consulta 4] Você tem um erro na sintaxe do SQL; verifique o manual que corresponde à versão do servidor MySQL para a sintaxe correta a ser usada perto de '- dest.lon) * pi () / 180/2), 2))) como distância FROM network_pos dest tendo d' na linha 2
Felipe
Olá, o @dist está em milles? obrigado
Jorge Olaf Erlandsen
11
Sim @OlafErlandsen está em milhas
Jan van der Vegt
4

Os tipos de dados de ponto estão OK; você pode simplesmente chamar X (coord) / Y (coord) para obter os valores de Lat / Lon.

Por exemplo:

SELECT id, 
(3959 
    * acos(
        cos(radians(37)) 
        * cos(radians(Y(coord)))
        * cos(radians(X(coord)) - radians(-122)) 
        + sin(radians(37))
        * sin(radians(Y(coord)))
      )
) AS distance 
FROM markers HAVING distance < 25 
ORDER BY distance LIMIT 20;
Shahak Nagiel
fonte
37 é lat e -122 é lon? E 25 é metros ou km?
Felipe
1

Encontre os 100 restaurantes mais próximos de alguma coordenada: Veja código eficiente em http://mysql.rjweb.org/doc.php/latlng Ele inclui uma função armazenada para calcular a distância "grande círculo".

Rick James
fonte