Como pesquiso com eficiência todos os pontos de referência dentro de um intervalo de um determinado ponto de referência?

14

Estou tentando começar com um projeto de pesquisa geográfica que encontrará todos os pontos de referência nos 10 km / milhas (não importantes para esta história) de um ponto de referência específico.

Por exemplo, digamos que eu tenha um banco de dados com 1.000.000 de pontos de referência. Para encontrar todos os pontos de referência no intervalo de 10 milhas de um ponto de referência com determinadas coordenadas, eu precisaria calcular a distância entre um ponto de referência da minha pesquisa e 1.000.000 pontos de referência.

Existe uma maneira melhor de fazer isso?

A alternativa que eu estava pensando é categorizar pontos de referência como país, região, cidade, bairro, empresa, histórico etc. de tal maneira que as empresas possam fazer parte de uma vizinhança ou cidade. A cidade faz parte de uma região, país, etc. Isso pode restringir uma lista de cálculos, mas ainda parece haver muito trabalho a fazer para que a pesquisa seja rápida e precisa.

A API do Google Maps poderia ajudar?

Dario Granich
fonte
5
Você provavelmente poderia eliminar muitos simplesmente executando um cálculo rápido da distância de Manhattan e, em seguida, executando um segundo filtro para excluir pontos de referência que estão dentro de um quadrado de 10 km, mas estão fora do raio de 10 km.
Neil
3
Qual tecnologia de banco de dados você está usando? A resposta não é independente do banco de dados.
Jpmc26 5/11
1
@ Neil Como uma segunda passagem, você pode incluir qualquer ponto de referência em que ambos x e y caiam em 7 km da origem, sem calcular a distância real.
precisa saber é o seguinte

Respostas:

10

Desde o SQL Server 2008, existe um tipo de dados geográficos que armazena locais (pares lat / lon) e facilita a gravação de consultas relacionadas ao local.

Existe uma resposta StackOverflow existente que discute isso em profundidade.

Uma consulta básica para encontrar os 7 itens mais próximos :

USE AdventureWorks2012  
GO  
DECLARE @g geography = 'POINT(-121.626 47.8315)';  
SELECT TOP(7) SpatialLocation.ToString(), City FROM Person.Address  
WHERE SpatialLocation.STDistance(@g) IS NOT NULL  
ORDER BY SpatialLocation.STDistance(@g);  

Uma consulta básica para encontrar tudo dentro de 100m (segunda resposta à pergunta)

-- Get the center point
DECLARE @g geography
SELECT @g = geo FROM yourTable WHERE PointId = something

-- Get the results, radius 100m
SELECT * FROM yourTable WHERE @g.STDistance(geo) <= 100
Flater
fonte
11
@KonradRudolph: como é o caso de qualquer coluna SQL usada para consultar uma tabela com um número de linhas massivo. Você está correto, mas esse comentário se aplicaria a praticamente qualquer consulta SQL publicada como resposta.
Flater
2
Onde você leu "MS SQL Server" na pergunta?
Doc Brown
3
@ Flater Concordo que seria normalmente óbvio e redundante, mas o texto do OP parece sugerir que eles não têm conhecimento de tais mecanismos.
Konrad Rudolph
2
@ jpmc26: Você está chocado por eu ter listado uma opção válida e não incluir outra opção? O que? Se você acha relevante adicionar o PostGIS, adicione a resposta você mesmo (o que você fez) e não recorra a criticar os outros por não terem a mesma idéia que você.
Flater
3
Sua resposta me parece basicamente apenas um discurso de vendas do MS SQL. Seus comentários sugerindo que eles mudem os bancos de dados para algo que custaria milhares de dólares, sem realmente perguntar qual é a situação deles. Ele nem sequer descreve como o OP pode realmente implementar sua consulta ou discutir o fato de que isso é feito e garantir que o índice espacial seja usado não é tão simples no MS SQL quanto em outros DBs. Também não discute nenhum dos conceitos subjacentes. É uma resposta ruim, independentemente de ser "válida". É por isso que me incomoda.
jpmc26
29

Use um banco de dados com suporte para consultas GIS (sistemas de informações geográficas) . A maioria dos bancos de dados suporta isso de imediato ou possui extensões, mas os detalhes serão específicos do banco de dados (na resposta , Flater mostra a sintaxe do SQL Server).

Se você precisar implementar essas consultas na sua aplicação, poderá implementar uma estrutura de dados que permita consultas espaciais, por exemplo, uma árvore kd . É como uma árvore de pesquisa binária, exceto que cada nível da árvore é particionado em uma dimensão de coordenada diferente. Isso permite restringir a pesquisa a um conjunto menor de candidatos possíveis. Efetivamente, você traduz sua pesquisa "raio de 10 km" em limites para cada dimensão de coordenada e os aperta conforme recua na árvore.

amon
fonte
5
Há também uma
troca de pilha
8
O PostGIS é a principal opção gratuita. Ele suporta muito, muito mais do que os tipos e funções GIS muito básicos do SQL Server. Mas essa é a funcionalidade básica.
Jpmc26
@amon Acho o comentário do jpmc26 como uma boa adição, e não tanto quanto criticar o seu exemplo. "Se você deseja começar do zero, não precisa pagar por um banco de dados licenciado - este de código aberto gratuito também fará o truque muito bem".
mgarciaisaia
11

Sim, existe uma maneira melhor. Você precisa usar um índice espacial . Esses índices organizam metadados sobre geometrias para filtrar geometrias distantes muito rapidamente, economizando muitos ciclos de CPU, evitando os cálculos que você descreve. Você não deve se preocupar em implementar um, pois todos os principais bancos de dados relacionais fornecem um tipo de geometria espacial e índices para acompanhá-los.

O que você deseja examinar são consultas "à distância" (consultas para geometrias a uma certa distância de outra geometria). Estes são muito padrão e muito um problema resolvido e são possíveis em todos os bancos de dados acima (e incorporados em vários):

  • PostGIS: ST_DWithin
  • SQL Server: STDistance(Não está claro que o uso de índice na versão geográfica 3D dessa função é suportada)
  • Oracle: SDO_WITHIN_DISTANCE(isso não diz explicitamente que ele acionará o uso do índice. Eu daria uma checada no plano de consulta. Pode ser necessário aplicar um SDO_FILTERpara fazê-lo usar o índice.)
  • MySQL: Ainda estou descobrindo isso.

Solução alternativa para acionar o uso do índice

No pior caso onde você tem problemas para obter o sistema para usar o índice espacial com estas consultas, você pode adicionar um filtro adicional. Você criaria uma caixa delimitadora quadrada com lados de comprimento 2 * (distância de pesquisa) centralizada no ponto de pesquisa e compararia as caixas delimitadoras das geometrias da tabela com essa antes de verificar a distância real. É o que o PostGIS ' ST_DWithinacima faz internamente de qualquer maneira.


Distância em SIG

Embora os índices espaciais sejam fantásticos e absolutamente a solução certa para o seu problema, o cálculo da distância pode ser logicamente complicado. Em particular, você precisa se preocupar com em qual projeção (basicamente todos os parâmetros do sistema de coordenadas) seus dados são armazenados. A maioria das projeções 2D (outras coisas que não os sistemas de coordenadas angulares, como as várias projeções latinas / longas) distorcem significativamente o comprimento. Por exemplo, a projeção Web Mercator (usada pelo Google, Bing e todos os principais fornecedores de mapas de base) expande áreas e distâncias cada vez mais à medida que a localização se afasta do do equador . Posso estar errado, pois não sou formalmente formado em SIG, mas o melhor que já vi para projeções em 2D são algumas específicas que prometem distâncias corretas de umponto único e constante em todo o mundo. (Não, não é prático usar uma projeção diferente para cada consulta; isso tornaria seus índices inúteis.)

A linha inferior é que você precisa ter certeza de que sua matemática está correta. A maneira mais simples de fazer isso da perspectiva do desenvolvimento é usar projeções angulares (geralmente chamadas de "geográficas") e funções que suportam a matemática usando um modelo de esferóide, mas esses cálculos são um pouco mais caros do que os equivalentes 2D e alguns bancos de dados podem não suportar a indexação deles. Se você pode obter um desempenho aceitável usando-os, esse provavelmente é o caminho a percorrer. Outra opção comum são as projeções regionais (como zonas UTM) que obtêm distâncias e áreas muito próximas da correção, se seus dados estiverem confinados a uma parte específica do mundo. O melhor para o seu aplicativo dependerá de seus requisitos específicos,

Isso se aplica mesmo se você não usar índices espaciais incorporados. Seus dados têm alguma projeção, independentemente de qual tecnologia ou técnica você está usando ou usa no futuro, e já está afetando as consultas e cálculos que você está fazendo no momento.

jpmc26
fonte
3

Concordo que, se possível, usar suporte específico em um banco de dados seria a maneira mais sensata de fazer isso.

No entanto, se eu tivesse que fazer isso em um banco de dados sem suporte específico, começaria consultando um quadrado que envolva a circulação, por exemplo (y> (y1 - rad)) AND (y <(y1 + rad)) AND (x> ( x1 - rad)) AND (x <(x1 + rad)). Supondo que seus pontos tenham praticamente a distribuição de consultas por um quadrado, você obterá suas correspondências verdadeiras e cerca de 30% de falsas extra. Você pode selecionar as correspondências falsas.

Peter Green
fonte
Porém, sem um índice espacial apropriado, essa consulta varrerá na pior das hipóteses todo o banco de dados, na melhor das hipóteses todos os itens dentro do intervalo de latitude OU longitude determinado, dependendo do seu índice, ou seja, uma "banda" em vez de um quadrado. Se você não quer diminuir o desempenho, use um banco de dados que suporte índices espaciais!
jcaron
@ jcaron Eu acredito que esta consulta poderia ser otimizada com um índice comum de árvore B em xe y. (Talvez combinados, talvez separar Eu perfil um pouco para descobrir qual funciona melhor na prática..)
jpmc26
@ jpmc26 Não, não pode. Pense bem, você verá.
jcaron
@ jcaron Talvez seria melhor se você não fosse enigmático sobre algo que claramente não é direto. Árvores B podem ser usadas para BETWEENconsultas. Não vejo por que, na pior das hipóteses, você não pode ter dois índices e, em seguida, os resultados filtrados de cada índice são reunidos. (Isso é algo que os RDBMSs fazem internamente quando consideram que vale a pena usar vários índices.) Se um índice combinado funcionar, ele deve filtrar uma dimensão inteiramente no primeiro nível e, em seguida, diminuir rapidamente no segundo nível.
precisa saber é o seguinte
2
@jcaron na verdade você pode usar o índice para algo como y between -68 and -69 and x between 10 and 11, mas do índice de curso espacial fazer um trabalho melhor para essa tarefa
Juan Carlos Oropeza