Tengo un conjunto de datos nacional de puntos de dirección (37 millones) y un conjunto de datos poligonales de contornos de inundación (2 millones) del tipo MultiPolygonZ, algunos de los polígonos son muy complejos, el máximo de ST_NPoints es de alrededor de 200,000. Estoy tratando de identificar usando PostGIS (2.18) qué puntos de dirección están en un polígono de inundación y escribirlos en una nueva tabla con identificación de dirección y detalles de riesgo de inundación. He intentado desde una perspectiva de dirección (ST_Within) pero luego cambié esto desde la perspectiva del área de inundación (ST_Contains), la razón es que hay grandes áreas sin riesgo de inundación. Ambos conjuntos de datos se han reproyectado a 4326 y ambas tablas tienen un índice espacial. ¡Mi consulta a continuación ha estado funcionando durante 3 días y no muestra signos de terminar pronto!
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);
¿Hay una forma más óptima de ejecutar esto? Además, para consultas de larga duración de este tipo, ¿cuál es la mejor manera de monitorear el progreso que no sea mirar la utilización de recursos y pg_stat_activity?
Mi consulta original terminó bien aunque durante 3 días y me desvié de otro trabajo, así que nunca pude dedicar el tiempo a probar la solución. Sin embargo, acabo de volver a visitar esto y de seguir las recomendaciones, hasta ahora todo bien. He usado lo siguiente:
- Creó una cuadrícula de 50 km sobre el Reino Unido utilizando la solución ST_FishNet sugerida aquí
- Establezca el SRID de la cuadrícula generada en British National Grid y construya un índice espacial en él
- Recorté mis datos de inundación (MultiPolygon) usando ST_Intersection y ST_Intersects (lo único que obtuve fue que tuve que usar ST_Force_2D en la geom ya que shape2pgsql agregó un índice Z
- Recorté mis datos de puntos usando la misma cuadrícula
- Se crearon índices en la fila y col e índice espacial en cada una de las tablas.
Estoy listo para ejecutar mi script ahora, iteraré sobre las filas y columnas que llenan los resultados en una nueva tabla hasta que haya cubierto todo el país. ¡Pero acabo de verificar mis datos de inundación y algunos de los polígonos más grandes parecen haberse perdido en la traducción! Esta es mi 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));
Mis datos originales se ven así:
Sin embargo, el recorte posterior se ve así:
Este es un ejemplo de un polígono "perdido":
fuente
Respuestas:
Para responder su última pregunta primero, vea esta publicaciónsobre la conveniencia de poder monitorear el progreso de las consultas. El problema es difícil y se agravaría en una consulta espacial, ya que saber que el 99% de las direcciones ya habían sido escaneadas para su contención en un polígono de inundación, que podría obtener del contador de bucle en la implementación de escaneo de la tabla subyacente, no necesariamente ayuda si el 1% final de las direcciones se cruza con un polígono de inundación con la mayoría de los puntos, mientras que el 99% anterior se cruza con un área pequeña. Esta es una de las razones por las que EXPLAIN a veces puede ser inútil con el espacio, ya que proporciona una indicación de las filas que se escanearán, pero, por razones obvias, no tiene en cuenta la complejidad de los polígonos (y, por lo tanto, una gran proporción del tiempo de ejecución) de cualquier consulta de tipo intersección / intersección.
Un segundo problema es que si miras algo como
verá algo así, después de perderse muchos detalles:
La condición final, &&, significa hacer una verificación de recuadro delimitador, antes de hacer una intersección más precisa de las geometrías reales. Esto es obviamente sensato y es el núcleo de cómo funcionan los R-Trees. Sin embargo, y también he trabajado en datos de inundaciones del Reino Unido en el pasado, así que estoy familiarizado con la estructura de los datos, si los polígonos (múltiples) son muy extensos; este problema es particularmente grave si un río corre a, digamos, 45 grados: obtienes enormes cuadros delimitadores, lo que podría forzar la verificación de un gran número de intersecciones potenciales en polígonos muy complejos.
La única solución que he podido encontrar para el problema "mi consulta ha estado ejecutándose durante 3 días y no sé si estamos al 1% o al 99%" es usar una especie de división y conquista para tontos. enfoque, con lo que quiero decir, divida su área en trozos más pequeños y ejecútelos por separado, ya sea en un bucle en plpgsql o explícitamente en la consola. Esto tiene la ventaja de cortar polígonos complejos en partes, lo que significa que el punto posterior en las comprobaciones de polígonos está trabajando en polígonos más pequeños y los cuadros delimitadores de los polígonos son mucho más pequeños.
Logré realizar consultas en un día dividiendo el Reino Unido en bloques de 50 km por 50 km, después de eliminar una consulta que se había estado ejecutando durante más de una semana en todo el Reino Unido. Como comentario aparte, espero que su consulta anterior sea CREATE TABLE o UPDATE y no solo SELECT. Cuando esté actualizando una tabla, las direcciones, en función de estar en un polígono de inundación, tendrá que escanear toda la tabla que se está actualizando, las direcciones de todos modos, por lo que tener un índice espacial no es de ninguna ayuda.
EDITAR: sobre la base de que una imagen vale más que mil palabras, aquí hay una imagen de algunos datos de inundaciones del Reino Unido. Hay un multipolígono muy grande, cuyo cuadro delimitador cubre toda esa área, por lo que es fácil ver cómo, por ejemplo, al intersecar primero el polígono de inundación con la cuadrícula roja, el cuadrado en la esquina suroeste de repente solo se probaría contra un pequeño subconjunto del polígono.
fuente