Problema do vizinho mais próximo no Postgis 2.0 usando o índice GIST (função <->)


25

Estou tentando usar a nova função do Postgis 2.0 <-> (Geometry Distance Centroid) para calcular, para cada linha da minha tabela (cosn1), a distância do polígono mais próximo da mesma classe.

Eu estava tentando usar o seguinte código:

WITH index_query AS (
  SELECT g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, g1.the_geom <-> g2.the_geom) 
SELECT DISTINCT ON (ref_gid) ref_gid, ENN 
    FROM index_query
ORDER BY ref_gid, ENN;

Mas então eu percebo o aviso:

Nota: O índice somente entra em ação se uma das geometrias for uma constante (não em uma subconsulta / cte). por exemplo, 'SRID = 3005; POINT (1011102 450541)' :: geometry em vez de a.geom

Significando que o Índice não será usado e a consulta levará quase o mesmo tempo que antes de usar:

SELECT DISTINCT ON(g1.gid)  g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom)

Alguém pode me indicar uma solução alternativa que me permita melhorar o desempenho da minha consulta?

Muito obrigado.


Ainda sem respostas, você pode perguntar isso na lista de discussão do PostGIS.
— GIS-Jonathan

Eu já fiz, mas também sem respostas.
— Alexandre Neto

3
Você pode usar g1.gid> g2.gid na cláusula where, que reduzirá o número de cálculos de distância que você precisa fazer. Infelizmente, até que o operador <-> funcione sem constantes, não veremos muita melhoria na velocidade nesse tipo de consulta.
— John Powell

John, preciso manter todos os gids, mesmo aqueles que são repetidos, pois preciso atualizar o EEN para cada um dos polígonos na minha tabela "cosn1". Mas o que você disse me deu uma ideia. Eu poderia fazer o que você diz usando g1.gid> g2.gis para reduzir os cálculos de distância, mas mantendo g1.gid e g2.gid no resultado. Depois disso, eu pude unir duas subconsultas (uma com g1.gis como gid e outra com g2.gid). Obrigado
— Alexandre Neto

Eu descobri que uma solução possível para solucionar o problema constante seria usar o <-> dentro de uma função SQL, usando the_geom como parâmetro. Fiz alguns testes e, em alguns casos, é muito mais rápido (). Mas no meu caso, como as distâncias estão dentro da mesma tabela, muitos cálculos de distância são repetidos durante o processo, tornando-o mais lento do que usando a consulta direta.
— Alexandre Neto

Respostas:


2

Hum fazendo alguns testes na minha máquina parecia que este operador <-> não está funcionando corretamente. Não tenho certeza de que seja um bug, mas ele relatou distância zero em geometrias não sobrepostas. Intrigante, não?

Bem, e as otimizações tradicionais tradicionais de consulta SQL? Como esses resultados inesperados com o operador <->, substituo-o por st_centroid. Obteve resultados muito melhores em velocidade.

Espero que a semântica com st_overlaps continue a mesma. Pelo menos isso foi compreendido na documentação sobre <->

Dos documentos no Postigs <->

Para outros tipos de geometria, a distância entre os centróides da caixa delimitadora de ponto flutuante é retornada.

Nos meus dados de teste com ~ 5.5k polígonos, a velocidade aumentou de ~ 1000 segundos para ~ 5 segundos sem indexação espacial.

Enfim, por que usar o DISTINCT ON para fazer agrupamentos? Vejo algumas pessoas usando, mas o grupo não existe para eliminar duplicatas?

Sua consulta com otimizações SQL padrão sem o erro st_centroid introduzido

select g1.gid, min( st_distance( g1.the_geom, g2.the_geom ) ) AS enn
FROM 
  "cosn1" AS g1, "cosn1" AS g2
WHERE
  g1.gid <> g2.gid
  AND g1.class = g2.class
  AND g1.the_geom && g2.the_geom
GROUP BY
  g1.gid

Feliz feriado de natal!


Desculpe, mas sua resposta não resolve o problema. Na verdade, é muito mais rápido, mas os resultados não são precisos, pois o resultado final é calculado usando os centróides dos polígonos, em vez de sua geometria real. O <-> visa otimizar a busca de candidatos ao vizinho mais próximo, mas no final deve usar as geometrias reais para calcular a distância dos melhores candidatos. Também tentei usar o MIN \ GROUP BY em vez do DISTINCT ON \ ORDER BY e parece mais lento.
— Alexandre Neto

Mas o manual postgis para o operador <-> afirma que ele usa o centróide para geometrias não pontuais. Portanto, minha solução forneceria resultados semelhantes. Deverá fornecer os mesmos resultados que sua consulta principal. Verifique se os resultados com o operador <-> também estão corretos. Ele me relatou geometrias de comprimento zero nos meus dados de teste para que os resultados pudessem ser quebrados e essa solução forneceu dados mais precisos. Se você conseguir publicar alguns registros de amostra mostrando erros em algum site de pastéis, poderemos descobrir falhas na solução.
— Cavila

Se você marcar minha consulta, o operador <-> seria usado apenas para solicitar os candidatos, o resultado final é calculado usando as geometrias reais. De qualquer forma, como eu disse antes, o <-> aumento de desempenho só funciona com pontos fixos. Essa foi a minha pergunta original.
— Alexandre Neto

Então, você concorda que a consulta superior não é equivalente à consulta inferior? Como a ordem mudará porque o operador <-> ORDER BY st_centroid e a st_distance fornecerão um valor diferente? Uma ordem diferente pode trazer uma consulta diferente como a primeira linha a transmitir na cláusula DISTINCT ON? A consulta válida seria a parte inferior que precisa melhorar a velocidade?
— Cavila

Sim, a primeira consulta é uma intenção de melhorar a velocidade na parte inferior. E sim, pode dar um resultado um pouco diferente, já que g1.geom <-> g2.geom usa os centróides, e isso significa que a primeira linha pode não estar mais próxima. Para fazê-lo funcionar, acredito que teria que colocar um limite na ordem por cláusula, digamos, limite 10 e depois extrair os valores reais da distância. Poderia até usar o <#>, que usa as caixas delimitadoras, em vez dos centróides.
— Alexandre Neto
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.