Rendimiento de ArcGISScripting y grandes conjuntos de datos espaciales

38

Actualmente estoy escribiendo un script de Python usando el módulo arcgisscripting para procesar un conjunto de datos razonablemente grande (~ 10,000 registros en total) normalizado en un pequeño número de tablas, 8 en total. El proceso consiste en crear una función basada en tuplas de coordenadas (x, y) y crear un gráfico (nodos y líneas) utilizando las relaciones en las otras 7 tablas como guía. El resultado final es una geodatabase personal (pgdb / fgdb) con nodos y conjuntos de datos espaciales de bordes que representan visualmente las relaciones.

Mi intento inicial fue utilizar consultas de las nuevas tablas de geodatabase y conjuntos de registros de SearchCursor para llenar tablas de enlaces (InsertCursor) para las relaciones de muchos a muchos que ocurren. Esto funcionó muy bien, excepto por el tiempo de procesamiento de 15-20 min.

Al usar el módulo cProfiler en Python, era evidente que 'sacudir' una geodatabase personal al realizar las consultas de búsqueda para llenar las tablas de enlaces con solicitudes de cursores (Buscar e Insertar cursores) causó un rendimiento terrible.

Con un poco de refactorización, he logrado que el tiempo de procesamiento sea inferior a 2.5 minutos. La compensación fue la construcción parcial del esquema de geodatabase en el código y la limitación de las solicitudes de cursores de arcgisscripting a InsertCursors una vez que se recopilaron todas las relaciones.

Mi pregunta es de rendimiento;

  • ¿Qué técnicas han usado las personas para mantener tiempos de cómputo razonables cuando trabajan con grandes conjuntos de datos?
  • ¿Hay algún método recomendado por ESRI que me haya perdido en mi búsqueda de optimización?

    Entiendo los gastos generales incurridos al crear un cursor de arcgisscripting, particularmente si es de una geodatabase personal, aunque después de una larga búsqueda de respuestas relacionadas con el rendimiento de este sitio y Google, tengo la impresión de que el rendimiento no está a la vanguardia de los esfuerzos de las personas. .

  • Como usuario de productos ESRI, ¿uno espera y aprueba estos retrasos de rendimiento?

ACTUALIZAR

Después de trabajar con este producto, he acumulado una lista de técnicas de optimización que han llevado a un proceso de conversión de información espacial de un formato de propiedad a una geodatabase. Esto ha sido desarrollado para geodatabase personal y de archivos. Cositas:

  1. Lee tus datos y racionalízalos en la memoria. Esto reducirá su tiempo a la mitad.

  2. Crear clases de entidad y tablas en la memoria. Use el trabajo de teclas del conjunto de datos de funciones 'in_memory' para usar su memoria como disco ram, realice sus funciones allí y luego escriba en el disco

  3. Para escribir en el disco, utilice CopyFeatureclass para clases de entidad y CopyRow para tablas.

Estas 3 cosas tomaron un script que convirtió más de 100,000 características en una geodatabase de 30 minutos a 30-40 segundos, esto incluye clases de relación. No deben usarse a la ligera, la mayoría de los métodos anteriores utilizan mucha memoria, lo que podría causar problemas si no presta atención.

OptimizePrime
fuente
1
¿Has intentado usar un formato de almacenamiento diferente? ¿Cómo funciona una geodatabase de archivos?
Derek Swingley
Una geodatabase de archivos funciona ligeramente peor que una geodatabase personal. Ayer pasé la configuración y el ajuste de una instancia de ArcSDE para probar el rendimiento en un formato empresarial. Los mantendré informados sobre mis hallazgos
OptimizePrime
2
Esto no te ayuda ahora, pero en 10.1 el rendimiento del cursor en Python ha sido mejorado por un factor enorme (algo en el orden de rango de magnitud en casos promedio) con el nuevo módulo de acceso a datos.
Jason Scheirer
In_memory usa un InMemoryWorkspace edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriDataSourcesGDB/… que, después de un número arbitrario de filas, volca todo a ScratchWorkspaceFactory (es decir, FileGDB) y confía en FileGDB para hacer todo el trabajo
Ragi Yaser Burhum

Respuestas:

56

Aunque esta pregunta ya fue respondida, pensé que podía sonar y dar mis dos centavos.

DESCARGO DE RESPONSABILIDAD : Trabajé para ESRI en el equipo de GeoDatabase durante algunos años y estaba a cargo de mantener varias partes del código de GeoDatabase (versiones, cursores, sesiones de edición, historia, clases de relación, etc.).

¡Creo que la mayor fuente de problemas de rendimiento con el código ESRI no es comprender las implicaciones del uso de diferentes objetos, en particular, los "pequeños" detalles de las diversas abstracciones de GeoDatabase! Muy a menudo, la conversación cambia al idioma que se utiliza como culpable de los problemas de rendimiento. En algunos casos puede ser. Pero no todo el tiempo. Comencemos con la discusión del idioma y trabajemos de regreso.

1.- El lenguaje de programación que eliges solo importa cuando estás haciendo algo complicado, en un ciclo cerrado. La mayoría de las veces, este no es el caso.

El gran elefante en la sala es que en el núcleo de todo el código ESRI, tienes ArcObjects, y ArcObjects está escrito en C ++ usando COM . Hay un costo por comunicarse con este código. Esto es cierto para C #, VB.NET, python o cualquier otra cosa que esté utilizando.

Usted paga un precio al inicializar ese código. Eso puede ser un costo insignificante si lo hace solo una vez.

Luego paga un precio por cada vez que interactúa con ArcObjects.

Personalmente, tiendo a escribir código para mis clientes en C #, porque es lo suficientemente fácil y rápido. Sin embargo, cada vez que quiero mover datos o hacer algún procesamiento para grandes cantidades de datos que ya están implementados en Geoprocesamiento , solo inicializo el subsistema de secuencias de comandos y paso mis parámetros. ¿Por qué?

  • Ya está implementado. Entonces, ¿por qué reinventar la rueda?
  • En realidad puede ser más rápido . "¿Más rápido que escribirlo en C #?" ¡Sí! Si implemento, digamos, carga de datos manualmente, significa que pago el precio de la conmutación de contexto .NET en un ciclo cerrado. Cada GetValue, Insert, ShapeCopy tiene un costo. Si hago una llamada en GP, ​​todo el proceso de carga de datos ocurrirá en la implementación real de GP - en C ++ dentro del entorno COM. No pago el precio por el cambio de contexto porque no hay ninguno, y por lo tanto es más rápido.

Ah, sí, entonces la solución es usar muchas funciones de geoprocesamiento. En realidad, tienes que tener cuidado.

2. GP es un cuadro negro que copia datos (potencialmente innecesarios) alrededor

Es una espada de doble filo. Es una caja negra que hace algo de magia internamente y escupe resultados, pero esos resultados a menudo se duplican. 100,000 filas se pueden convertir fácilmente en 1,000,000 filas en el disco después de ejecutar sus datos a través de 9 funciones diferentes. Usar solo funciones GP es como crear un modelo GP lineal, y bueno ...

3. Encadenar demasiadas funciones GP para grandes conjuntos de datos es altamente ineficiente. Un modelo GP es (potencialmente) equivalente a ejecutar una consulta de una manera realmente muy tonta

Ahora no me malinterpretes. Me encantan los modelos GP: me evita escribir código todo el tiempo. Pero también soy consciente de que no es la forma más eficiente de procesar grandes conjuntos de datos.

¿Has oído hablar de un planificador de consultas ? Su trabajo es mirar la declaración SQL que desea ejecutar, generar un plan de ejecución en forma de un gráfico dirigido que se parezca mucho a un modelo GP , mirar las estadísticas almacenadas en la base de datos y elegir la mayoría orden óptimo para ejecutarlos . GP solo las ejecuta en el orden en que las coloca porque no tiene estadísticas para hacer nada de manera más inteligente: usted es el planificador de consultas . ¿Y adivina qué? El orden en el que ejecuta las cosas depende mucho de su conjunto de datos. El orden en el que ejecuta las cosas puede marcar la diferencia entre días y segundos y eso depende de usted decidir.

"Genial", dices, no escribiré las cosas yo mismo y seré cuidadoso sobre cómo escribo cosas. ¿Pero entiendes las abstracciones de GeoDatabase?

4. No entender las abstracciones de GeoDatabase puede morderte fácilmente

En lugar de señalar cada cosa que posiblemente pueda darte un problema, permíteme señalar algunos errores comunes que veo todo el tiempo y algunas recomendaciones.

  • Comprender la diferencia entre verdadero / falso para reciclar cursores . Esta pequeña bandera configurada como verdadera puede hacer que los órdenes de magnitud de tiempo de ejecución sean más rápidos.
  • Ponga su tabla en LoadOnlyMode para cargas de datos. ¿Por qué actualizar el índice en cada inserción?
  • Comprenda que aunque IWorkspaceEdit :: StartEditing se ve igual en todos los espacios de trabajo, son bestias muy diferentes en cada fuente de datos. En un Enterprise GDB, puede tener versiones o soporte para transacciones. En los archivos de forma, tendrá que implementarse de una manera muy diferente. ¿Cómo implementaría Deshacer / Rehacer? ¿Incluso necesita habilitarlo (sí, puede marcar la diferencia en el uso de la memoria).
  • La diferencia entre operaciones por lotes u operaciones de una sola fila. Caso en cuestión GetRow vs GetRows : esta es la diferencia entre hacer una consulta para obtener una fila o hacer una consulta para obtener varias filas. Un ciclo cerrado con una llamada a GetRow significa un rendimiento horrible y es el culpable # 1 de problemas de rendimiento
  • Utilice UpdateSearchedRows
  • Comprenda la diferencia entre CreateRow y CreateRowBuffer . Gran diferencia en el tiempo de ejecución del inserto.
  • Comprenda que IRow :: Store y IFeature :: Store activan operaciones polimórficas súper pesadas . Esta es probablemente la razón # 2 culpable de un rendimiento realmente lento. No solo guarda la fila, este es el método que asegura que su red geométrica esté bien, que ArcMap Editor reciba una notificación de que una fila ha cambiado, que notifica a todas las clases de relación que tienen algo que ver con esta fila validar para hacer asegúrese de que la cardinalidad sea válida, etc. ¡No debería insertar nuevas filas con esto, debería usar un cursor de inserción !
  • ¿Desea (necesita) hacer esas inserciones en una sesión de edición? Hace una gran diferencia si lo haces o no. Algunas operaciones lo requieren (y hacen las cosas más lentas), pero cuando no lo necesite, omita las funciones de deshacer / rehacer.
  • Los cursores son recursos caros. Una vez que tenga un identificador para uno, se le garantiza que tendrá Consistencia y Aislamiento y eso tiene un costo.
  • Guarde en caché otros recursos como conexiones de base de datos (no cree y destruya su referencia de espacio de trabajo) y controladores de tabla (cada vez que abra o cierre uno, se deben leer varias tablas de metadatos).
  • Poner FeatureClasses dentro o fuera de un FeatureDataset hace una gran diferencia en el rendimiento. Se no se entiende como una característica de la organización!

5. Y por último y no menos importante ...

Comprender la diferencia entre las operaciones vinculadas de E / S y CPU

Honestamente, pensé en expandirme más en cada uno de esos elementos y tal vez hacer una serie de entradas de blog que cubrieran cada uno de esos temas, pero la lista de trabajo pendiente de mi calendario me abofeteó y comenzó a gritarme.

Mis dos centavos.

Ragi Yaser Burhum
fuente
55
Gracias. Debería haber estado trabajando en lugar de escribir esta publicación jaja
Ragi Yaser Burhum
3
+1 Muchas gracias por su aporte Sr. Burhum. Este es el tipo de respuesta que pretendía recibir. ¡Si pudiera votarlo dos veces podría! Lo que los usuarios de ArcGISScripting (python) deben tomar de esta respuesta es que, aunque los enlaces reflejan los conceptos de ArcObjects y .Net, los objetos COM subyacentes son los mismos, comprender estos objetos lo ayudará a planificar mejor el código en cualquier idioma. Mucha información genial aquí !!
OptimizePrime
1
@OptimizePrime Ese es un gran resumen. Y tiene razón: no puede ignorar las implicaciones de ArcObjects si desea exprimir el rendimiento de los productos ESRI
Ragi Yaser Burhum
1
¡Gracias, reemplacé store () por insertar cursores y ahorré mucho tiempo en mis aplicaciones!
superrache
5

En general, para los cálculos de rendimiento, trato de evitar el uso de cualquier material relacionado con ESRI. Para su ejemplo, sugeriría hacer el proceso en pasos, el primer paso leyendo los datos en objetos python normales, haciendo los cálculos, y luego el paso final convirtiendo al formato espacial ESRI final. Para ~ 10k registros, probablemente podría evitar almacenar todo en la memoria para el procesamiento, lo que le daría una ganancia de rendimiento definitiva.

Anthony -GISCOE-
fuente
Gracias por su respuesta. Es una buena sugerencia. Comencé a refactorizar el código para realizar los procedimientos requeridos antes de usar arcgisscripting. Después de trabajar con el software desde sus días de ArcInfo, encuentro frustrante que el rendimiento de la CPU y la capacidad del hardware aumenten, el rendimiento de ArcGIS Map / Info / Editor XX está estancado. Tal vez la introducción de GPU puede impulsar las cosas. Aunque una buena refactor de la base de código de ESRI puede ayudar también
OptimizePrime
1

Dependiendo del hardware que tenga, también puede considerar la opción que se muestra en el ejemplo del geocodificador ESRI; le brinda un marco para dividir un gran conjunto de datos y ejecutar varias instancias de python para brindarle un enfoque de subprocesos múltiples. Vi que el rendimiento de la geocodificación pasó de 180,000 por hora en una sola instancia de Python a más de un millón gracias a la aceleración de 8 procesos paralelos en mi máquina.

He visto que alejarme tanto como puedo y mantener el trabajo de los datos en la base de datos, y el trabajo funcional en mis tablas y solo usar lo que es SIG explícito en el ámbito de ESRI, aumentan considerablemente el rendimiento.

DEWright
fuente
Estas son buenas ideas. Tengo la oportunidad de enhebrar algunos procesos en este script, pero descubro que mis cuellos de botella están inicializando las bibliotecas COM y la E / S de Geodatabase. En lo que respecta a E / S, he reducido la necesidad de una sola escritura. Si paso más tiempo optimizando, mi jefe tendrá un ataque;) Así que dejo el subproceso como el último apretón de rendimiento si me pide más. En este momento estoy procesando 60,000 funciones por minuto.
OptimizePrime
0

Puede que estas otras publicaciones del foro le resulten interesantes, ya que se encuentran en el contexto de optimización, pero para los datos ráster y en general:

¿Compilando scripts de Python que usan herramientas de geoprocesamiento de ArcGIS?

¿Tiempo de procesamiento usando las herramientas de la caja de herramientas de ArcGIS Hydrology en el script independiente de Python vs ArcCatalog?

La configuración de gp.scratchworkspace hizo una gran diferencia para mí en algún código de Python que escribí para hacer delineaciones de cuencas hidrográficas.

¿Podría publicar algunos ejemplos de código que demuestren los números 1 y 2 en su ACTUALIZACIÓN a su pregunta original? Me interesaría ver la mecánica de eso (aunque supongo que solo se trata de datos de clase de entidad aquí)

gracias Tom

oro turco
fuente