Estou procurando otimizar o tempo de pesquisas geográficas de proximidade de pontos.
Minha entrada é lat, lng point e estou pesquisando em um conjunto pré-computado de locais para n pontos mais próximos.
Não me importo quanto tempo / espaço a construção do índice pré-computado de locais levará, mas me importo que as consultas sejam super rápidas.
Estou pensando em usar o geohash como a chave de pesquisa, onde primeiro verificaria se obtive resultados para X caracteres da chave e continuaria a reduzir caracteres do final da chave até começar a ver os resultados.
Para meu entendimento (muito escasso por enquanto) das técnicas de índice geográfico, essa abordagem deve ser capaz de produzir os resultados mais rápidos (em termos de tempo de consulta) em comparação com todas as outras implementações conhecidas (como R Tree e companhia).
Respostas:
Absolutamente você pode. E isso pode ser bastante rápido. (Os bits intensivos de computação também podem ser distribuídos)
Existem várias maneiras, mas uma delas com a qual estou trabalhando é usar uma lista ordenada de geohashes baseadas em números inteiros e encontrar todos os intervalos de geohash vizinhos mais próximos para uma resolução específica de geohash (a resolução se aproxima de seus
distance
critérios) e, em seguida, consultando esses intervalos de geohash para obter uma lista de pontos próximos. Eu uso redis e nodejs (isto é, javascript) para isso. O Redis é super rápido e pode recuperar intervalos ordenados muito rapidamente, mas não pode executar muitas das tarefas de manipulação de consulta de indexação que os bancos de dados SQL podem fazer.O método está descrito aqui: https://github.com/yinqiwen/ardb/wiki/Spatial-Index
Mas a essência disso é (parafraseando o link):
Você pode otimizar ainda mais (velocidade) isso:
Você pode melhorar ainda mais a precisão usando uma função de distância do círculo / tipo haversine nos resultados retornados se você se preocupa muito com a precisão.
Aqui está uma técnica semelhante usando geohashes base32 comuns e uma consulta SQL em vez de redis: https://github.com/davetroy/geohash-js
Não pretendo conectar minhas coisas, mas escrevi um módulo para nodejs & redis que facilita muito a implementação. Dê uma olhada no código, se você quiser: https://github.com/arjunmehta/node-georedis
fonte
A pergunta pode ser lida de várias maneiras. Interpreto que isso significa que você tem um grande número de pontos e pretende sondá-los repetidamente com pontos arbitrários, dados como pares de coordenadas, e deseja obter os n pontos mais próximos da sonda, com n fixado previamente. (Em princípio, se n variar, você poderá configurar uma estrutura de dados para todos os n possíveis e selecioná-la no tempo O (1) com cada análise: isso pode levar um tempo de configuração muito longo e exigir muita RAM, mas nós são instruídos a ignorar essas preocupações.)
Crie o diagrama Voronoi de ordem n de todos os pontos. Isso divide o plano em regiões conectadas, cada uma com os mesmos n vizinhos. Isso reduz a situação ao problema do ponto no polígono, que tem muitas soluções eficientes.
Usando uma estrutura de dados vetoriais para o diagrama de Voronoi, as pesquisas point-in-polygon levarão tempo O (log (n)). Para fins práticos, você pode fazer esse O (1) com um coeficiente implícito extremamente pequeno, simplesmente criando uma versão rasterizada do diagrama. Os valores das células na varredura são: (i) um ponteiro para uma lista dos n pontos mais próximos ou (ii) uma indicação de que essa célula se estende por duas ou mais regiões no diagrama. O teste para um ponto arbitrário em (x, y) se torna:
Para obter o desempenho O (1), a malha rasterizada deve ser suficientemente fina para que relativamente poucos pontos de sonda caiam nas células que atravessam várias regiões de Voronoi. Isso sempre pode ser realizado, com uma despesa potencialmente grande em armazenamento para as grades.
fonte
Eu uso geohashes exatamente para isso. A razão de eu ser é porque eu precisava implementar pesquisas de proximidade usando um sistema de informações no estilo pirâmide .. onde geohashes com precisão de 8º nível eram a 'base' e formava novos totais para geohashes de 7ª precisão ... e assim por diante. . Esses totais foram área, tipos de cobertura do solo, etc. Era uma maneira muito sofisticada de fazer coisas muito sofisticadas.
Portanto, as geohashes do 8º nível conteriam informações como:
tipo: grama acres: 1,23
e 7, 6, etc., etc. conteriam informações como:
Tipo de grama: 123 acres: 6502
Isso sempre foi construído com a menor precisão. Isso me permitiu fazer todo tipo de estatística divertida muito rapidamente. Também pude atribuir uma referência de geometria a cada referência de geohash usando GeoJSON.
Consegui escrever várias funções para encontrar as maiores geohashes que compõem minha viewport atual e depois usá-las para encontrar geohashes da segunda maior precisão dentro da viewport. Isso poderia ser facilmente estendido para consultas de intervalo indexado, nas quais eu solicitaria um mínimo de '86ssaaaa' e um máximo de '86sszzzz' para qualquer precisão que eu quisesse.
Estou fazendo isso usando o MongoDB.
fonte
Atualização para 2018 e algumas fundações matemáticas ou proveniência histórica de Geohash:
a inspiração para Geohash foi o interlave simples de dígitos binários , talvez uma optimização de algoritmos ingênuos que intercalados dígitos decimais, como o de C-quadrados .
Como o entrelaçamento binário resultou em uma estratégia de índice de curva de ordem Z naturalmente, o inventor do Geohash não começou a "procurar a melhor curva fractal" ... Mas, curiosamente, essa otimização de design, uma melhor curva fractal, é possível (!).
Usar biblioteca de geometria S2
A abordagem da geometria S2 é melhor que o Geohash, porque usa a topologia esférica do mundo (um cubo), usa projeção opcional (para que todas as células tenham quase a mesma forma e a área próxima) e porque a indexação com a curva de Hilbert é melhor que Z- curva de ordem :
Agora é uma biblioteca gratuita e eficiente, consulte https://s2geometry.io
PS: também existem (boas) versões simplificadas não oficiais como NodeJS
s2-geometry
e muitos "playgrounds", suplementos e demos, como s2.sidewalklabs.com .fonte
Eu recomendaria usar a consulta GEORADIUS em redis.
Envie os dados agrupados pelo nível de geohash mais adequado usando a chamada GEOADD.
Além disso, dê uma olhada neste -> ProximityHash .
O ProximityHash gera um conjunto de geohashes que cobrem uma área circular, dadas as coordenadas do centro e o raio. Ele também possui uma opção adicional para usar o GeoRaptor, que cria a melhor combinação de geohashes em vários níveis para representar o círculo, começando do nível mais alto e repetindo até que a mistura ideal seja preparada. A precisão do resultado permanece a mesma do nível inicial de geohash, mas o tamanho dos dados reduz consideravelmente, melhorando assim a velocidade e o desempenho.
fonte