5 votos

¿Escalando DA UpdateCursor a conjuntos de datos grandes?

Actualmente estoy teniendo lo que parece ser un problema de escalado con arcpy, actualización de cursores de da y grandes geodatabases de archivos.

Tengo un fragmento de código que itera a través de cada elemento en una clase de elementos y realiza algunos cálculos y manipulaciones en los datos. Funciona muy bien para conjuntos de datos más pequeños, pero es órdenes de magnitud más lento en los grandes. Tengo un contador simple y declaraciones de impresión cada 1000 registros con el propósito de hacer una evaluación y estos son los resultados:

  • 48k elementos, cada 1000 tarda ~0.12 segundos en hacer
  • 133k elementos, cada 1000 tarda ~0.12 segundos en hacer
  • 2 millones de elementos, cada 1000 tarda ~0.17 segundos en hacer
  • 48 millones de elementos, cada 1000 tarda ~23 segundos en hacer (sí, veintitrés segundos, sin lugar decimal)

Solo dejé correr los 48 millones durante unos minutos antes de detenerlo, pero el resto se ejecutaron hasta completarse y estos tiempos son muy consistentes, ya sea el primero o el último, con solo unos centésimos de desviación de vez en cuando. Incluso si estuvieran escalando linealmente, solo esperaría .05 segundos cada 2 millones de registros y eso pondría los 48 millones en algún lugar del área de 1.3 segundos. Los resultados son 20 veces eso.

Los que tienen menos elementos son solo subconjuntos de los datos para fines de prueba, por lo que no debería ser un problema con diferencias en los datos. Todos fueron creados de la misma manera, por lo que no creo que haya un problema con diferencias en los datos aparte del tamaño. Parece que proviene puramente del número de elementos.

Lo siento, no tengo el código exacto conmigo en este momento, está en el trabajo, pero esto es básicamente esto. El código en sí funciona bien, sin embargo, me pregunto si alguien ha tenido problemas similares con grandes conjuntos de datos. Pensaba que podría ser un error de fuga de memoria, pero todos estos se ejecutan fuera de Arc en la ventana de python y esperaría que una fuga de memoria tomaría tiempo para aumentar (ralentizar) con el tiempo en lugar de ser instantáneamente mucho más lento.

import arcpy
from datetime import datetime

...

i = 0
fromlast = datetime.now()
with arcpy.da.UpdateCursor(fc, fields) as rows:
    for row in rows:
        if i % 1000 == 0:
            now = datetime.now()
            print i, ': ', now - fromlast
            fromlast = now
        ###hacer cosas aquí
        rows.updateRow(row)
        i += 1

Solo tengo ArcGIS (licencia de ArcInfo), gdal/ogr2ogr y python para trabajar, pero no estoy fijo en usar el FGDB o cursores da si hay una mejor manera de hacerlo dentro de mi selección limitada de herramientas.

2voto

Örjan Jämte Puntos 3127

¿Crear un índice tiene algún impacto en el tiempo de ejecución?

También puedes usar una instrucción SQL para restringir los valores a los que estás accediendo. Si realmente necesitas acceder a una gran cantidad de datos, puedes anidar la instrucción SQL y el cursor dentro de un bucle while.

Edición: He realizado algunas pruebas en mi máquina (Windows 7 x64, 2.4GHz i3-370m (lol), 8GB de RAM, ArcMap 10.1 SP1). Creé una clase de entidad de 25,000,000** filas con un campo, x, que contiene enteros secuenciales. Supongo que los cursores de actualización son más lentos, por lo que es por eso que probé un cursor de búsqueda.

import arcpy, time    
shp = "C:/images/junk/massive.gdb/large"
entries = int(arcpy.GetCount_management(shp).getOutput(0))
test1 = []
startval = 0
breakval = 1000000   

c = time.clock()
while startval < entries:       
    sql = '"OBJECTID" BETWEEN {0} AND {1}'.format(startval+1, startval+breakval)
    test1.extend([row[0] for row in arcpy.da.SearchCursor(shp, "x", sql)])
    startval+=breakval
print time.clock()-c

c = time.clock()
test2 = [row[0] for row in arcpy.da.SearchCursor(shp, "x")]
print time.clock()-c

print test1 == test2

Los resultados fueron los siguientes:

614.128610407
601.801415697
True

Esto colocaría mi tiempo de lectura en ~41,000 registros/s o 1,000 registros en ~24.4 µs.

**Ejecuté test1 con 50,000,000 entidades y tomó 1217. No pude ejecutar test2 ya que recibí un error de desbordamiento de memoria. Pero de todos modos, duplicé las entidades y el tiempo se duplicó aproximadamente, lo cual es alentador.

No estoy seguro del punto de corte donde el tiempo de acceso se dispara, pero si esto es algo que estarás ejecutando a menudo, vale la pena optimizar breakval. Para hacer eso, aumenta/disminuye breakval y simplemente accede a un subconjunto de tu FC con SQL una vez (el FC completo claramente tarda demasiado). Si tiempo de ejecución total*entidades/breakval disminuye entre ejecuciones, entonces puedes seguir ajustando breakval.

1voto

John Kramlich Puntos 286

Actualmente estoy tratando de procesar algunas featureclasses muy grandes con un script de actualización, una simple búsqueda y reemplazo en 5 campos en un conjunto de datos de 13 millones de filas. Mi código se estaba ejecutando terriblemente lento y leyendo esto y el foro de geonet llegué a la conclusión de que necesitaba agrupar mi procesamiento para que mi cursor de actualización utilice una cláusula where y avance sobre 50,000 filas a la vez. Pero esto no mejoró las cosas, luego se me ocurrió la idea de eliminar los índices de atributos que estaban en 3 de los 5 campos. ¡Eso realmente hizo la diferencia!

Así que mi consejo es que si estás actualizando featureclasses monstruosas ¡elimina los índices de atributos!

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X