Otimizando um ponto muito grande na consulta de polígono

9

Eu tenho um conjunto de dados nacional de pontos de endereço (37 milhões) e um conjunto de dados poligonais de contornos de inundação (2 milhões) do tipo MultiPolygonZ, alguns dos polígonos são muito complexos, o máximo de ST_NPoints é de cerca de 200.000. Estou tentando identificar usando o PostGIS (2.18) quais pontos de endereço estão em um polígono de inundação e escrevê-los em uma nova tabela com identificação de endereço e detalhes de risco de inundação. Tentei de uma perspectiva de endereço (ST_Within), mas depois troquei isso a partir da perspectiva da área de inundação (ST_Contains), justificando que existem grandes áreas sem risco de inundação. Ambos os conjuntos de dados foram reprojetados para 4326 e as duas tabelas possuem um índice espacial. Minha consulta abaixo está em execução há 3 dias e não mostra sinais de conclusão tão cedo!

select a.id, f.risk_factor_1, f.risk_factor_2, f.risk_factor_3
into gb.addresses_with_flood_risk
from gb.flood_risk_areas f, gb.addresses a
where ST_Contains(f.the_geom, a.the_geom);

Existe uma maneira mais ideal de executar isso? Além disso, para consultas de longa execução desse tipo, qual é a melhor maneira de monitorar o progresso, além de observar a utilização de recursos e a pg_stat_activity?


Minha consulta original terminou em OK, embora por três dias, e me desviei de outros trabalhos, para que eu nunca dedicasse tempo à tentativa da solução. No entanto, eu apenas visitei isso novamente e trabalhei com as recomendações, até agora tão boas. Eu usei o seguinte:

  1. Criou uma grade de 50 km no Reino Unido usando a solução ST_FishNet sugerida aqui
  2. Defina o SRID da grade gerada como British National Grid e construa um índice espacial nela
  3. Recortei meus dados de inundação (MultiPolygon) usando ST_Intersection e ST_Intersects (só peguei aqui foi preciso usar ST_Force_2D no geom, pois shape2pgsql adicionou um índice Z
  4. Recortou meus dados de ponto usando a mesma grade
  5. Criamos índices na linha e índice col e espacial em cada uma das tabelas

Estou pronto para executar meu script agora, iterará nas linhas e colunas que preenchem os resultados em uma nova tabela até que eu cubra todo o país. Mas acabei de verificar meus dados de inundação e alguns dos maiores polígonos parecem ter sido perdidos na tradução! Esta é a minha consulta:

SELECT g.row, g.col, f.gid, f.objectid, f.prob_4band, ST_Intersection(ST_Force_2D(f.geom), g.geom) AS geom 
INTO rofrse.tmp_flood_risk_grid 
FROM rofrse.raw_flood_risk f, rofrse.gb_grid g
WHERE (ST_Intersects(ST_Force_2D(f.geom), g.geom));

Meus dados originais são assim:

Dados originais de inundação

No entanto, após o recorte, fica assim:

Dados de inundação em grade

Este é um exemplo de um polígono "ausente":

Polígono "ausente"

Mark Varley
fonte
Eu só percebi que nós nos encontramos na FOSS4G em Seul e falou sobre as maravilhas da ESRI hub localizador :-)
John Powell
Você já terminou a abordagem de dividir e conquistar? Você pode atualizar os tempos de referência com essa abordagem?
andrew

Respostas:

6

Para responder à sua última pergunta primeiro, consulte esta postagemsobre a conveniência de poder monitorar o progresso das consultas. O problema é difícil e seria composto em uma consulta espacial, pois saber que 99% dos endereços já haviam sido varridos para contenção em um polígono de inundação, que você poderia obter do contador de loop na implementação da varredura de tabela subjacente, não necessariamente ajuda se o 1% final de endereços cruzar um polígono de inundação com mais pontos, enquanto os 99% anteriores cruzam alguma área minúscula. Essa é uma das razões pelas quais EXPLAIN às vezes pode ser inútil em termos espaciais, pois fornece uma indicação das linhas que serão verificadas, mas, por razões óbvias, não leva em conta a complexidade dos polígonos (e, portanto, uma grande proporção do tempo de execução) de quaisquer consultas de tipo de interseção / interseção.

Um segundo problema é que, se você olhar para algo como

EXPLAIN 
SELECT COUNT(a.id) 
FROM sometable a, someothertable b
WHERE ST_Intersects (a.geom, b.geom)

você verá algo como, depois de perder muitos detalhes:

_st_intersects(a.geom, b.geom)
   ->  Bitmap Index Scan on ix_spatial_index_name  (cost...rows...width...))
   Index Cond: (a.geom && geom)

A condição final, &&, significa fazer uma verificação na caixa delimitadora, antes de fazer uma interseção mais precisa das geometrias reais. Isso é obviamente sensato e está no centro de como as R-Trees funcionam. No entanto, e eu também trabalhei com dados de inundação do Reino Unido no passado, por isso estou familiarizado com a estrutura dos dados, se os (Multi) polígonos forem muito extensos - esse problema é particularmente grave se um rio correr, digamos, 45 graus - você recebe enormes caixas delimitadoras, o que pode forçar um grande número de interseções em potencial a serem verificadas em polígonos muito complexos.

A única solução que consegui encontrar para o problema "minha consulta está em execução há 3 dias e não sei se estamos com 1% ou 99%" é usar uma espécie de divisão e conquista para manequins abordagem, com o que quero dizer, divida sua área em partes menores e execute-as separadamente, em um loop no plpgsql ou explicitamente no console. Isso tem a vantagem de cortar polígonos complexos em partes, o que significa que pontos subseqüentes nas verificações de polígonos estão trabalhando em polígonos menores e as caixas delimitadoras dos polígonos são muito menores.

Consegui executar consultas em um dia dividindo o Reino Unido em blocos de 50 km por 50 km, depois de matar uma consulta que estava em execução há mais de uma semana em todo o Reino Unido. Como um aparte, espero que sua consulta acima seja CREATE TABLE ou UPDATE e não apenas um SELECT. Quando você estiver atualizando uma tabela, endereços, com base em um polígono de inundação, será necessário varrer toda a tabela que está sendo atualizada, endereços de qualquer maneira, portanto, na verdade, ter um índice espacial nela não ajuda em nada.

EDIT: Com base em que uma imagem vale mais que mil palavras, aqui está uma imagem de alguns dados de inundação no Reino Unido. Há um multipolígono muito grande, cuja caixa delimitadora cobre toda a área; é fácil ver como, por exemplo, ao cruzar primeiro o polígono de inundação com a grade vermelha, o quadrado no canto sudoeste seria repentinamente testado contra um pequeno subconjunto do polígono.

insira a descrição da imagem aqui

John Powell
fonte
Olá John, e muito obrigado pela resposta abrangente, seguirei sua recomendação sobre a abordagem de grade, soa como uma sugestão muito sensata, não quero realmente simplificar e perder precisão. Vou fazer benchmark com um bloco e depois executar em paralelo, muito mais fácil hoje em dia com a nuvem! Mais uma vez obrigado
Mark Varley
Olá Mark, não se preocupe, considere aceitar a resposta se achar que ela ajudou. Isso ajuda a manter o site limpo, perguntas sem respostas aceitas são uma das métricas analisadas pelos sites de troca.
John Powell
OK, tudo pronto, este é o meu primeiro post aqui, normalmente encontro a resposta nos tópicos detalhados e nas respostas úteis. A consulta finalmente terminou esta manhã após cerca de três dias, o que não é muito ruim, mas seguirá seu conselho hoje e o dividirá em pedaços para obter melhor desempenho. Mais uma vez obrigado pela sua ajuda, John, e talvez até em Bonn em agosto!
precisa
Adicionei uma foto, apesar de perceber que você conseguiu a foto: D, isso pode ajudar outras pessoas a visualizar o que estou falando. Sim, eu certamente estou indo para o Foss4G do Reino Unido e pensarei em Bonn.
John Powell