ArcView 3.x Avenue Bitmaps (Tabs?) Vs. ArcView 10 Python Cursors


9

Remarque: Bien que cette question ait une réponse, tout autre conseil pour optimiser un processus de curseur serait grandement apprécié. Je surveillerai les mises à jour.

Actuellement, mon patron (qui travaille dans Avenue) et moi (travaillant en Python) essayons tous les deux de résoudre le même problème. Nous l'avons plutôt résolu tous les deux, mais la vitesse à laquelle nos solutions fonctionnent est ... disjointe, c'est le moins que l'on puisse dire. Ce que son script traite en 2 heures peut prendre le mien jusqu'à 6. La seule vraie différence de syntaxe et d'implémentation en logique vient des Bitmaps 3.x et des curseurs 10.x. Tous les deux:

1) Stockez les valeurs du tableau 1.
2) Utilisez ces valeurs pour interroger une ligne du tableau 2.
3) Stockez les valeurs du tableau 2 pour les insérer dans le tableau 3 en tant que nouvelle ligne.

Dans les deux scripts, ces processus sont exécutés en deux boucles imbriquées. Avant de commencer à creuser dans le monde merveilleux de l'optimisation de code, est-ce un événement attendu lors de la comparaison des performances du script Avenue avec Python? Ce n'est pas la première fois que ses scripts surpassent largement les miens en termes de temps de fonctionnement, donc je voudrais savoir s'il y a quelque chose que je devrais savoir avant de me crucifier pour des scripts horribles.

Voici mon script sans bits étrangers:

import arcpy
import time
import sys
import os

def recordfindcopy(inFile,query,outFile):
    findRecord = arcpy.SearchCursor(inFile,query)
    for record in findRecord:
        copyRecord = arcpy.InsertCursor(outData) # <--- D'oh! (See answer)
        field = record.FIELD
        copy = copyRecord.newRow()
        copy.FIELD = field
        copyRecord.insertRow(copy)

StreetsFileList = [r"Path", 
                r"Path"]

for sfile in StreetsFileList:
    inStreets = sfile
    inTable = r"Path"
    outData = r"Path"
    fsaEntry = arcpy.SearchCursor(inTable)
    for row in fsaEntry:
        id = row.ID
        sQuery = "ID = %s " % (str(id))
        recordfindcopy(inStreets,sQuery,outData)

EDIT : Compte tenu de certains commentaires jusqu'à présent, je me demande s'il pourrait y avoir une meilleure façon de le faire via les jointures, bien que je sois douteux compte tenu de la taille brobdingnagienne (mot du jour!) Des tables. Le cœur du traitement consiste à ajouter des informations d'une table à tous les enregistrements correspondants d'une deuxième table et à créer une troisième table contenant uniquement les champs importants. Je voulais essayer ceci en utilisant SDE, mais cela ne semble pas être une option disponible. Pensées? Je m'excuse si mes questions sont toujours aussi compliquées , mais j'essaie d'aller au fond d'un agacement de longue date.

Réponse : la simple suggestion de Jakub a réduit à elle seule le temps de traitement de 30 secondes pour 500 enregistrements à 3 secondes pour 500 enregistrements. La réinitialisation du curseur d'insertion sur chaque insert a considérablement ralenti les choses (évidemment). Bien que ce ne soit peut-être pas le plus d'optimisation possible pour ce processus lorsqu'il est mis en place contre la vitesse d'ArcView 3.x, c'est suffisant pour mes besoins en ce moment. D'autres suggestions sont les bienvenues!


1
Envie de poster votre script? Je ne connais aucune avenue / python utilisant des benchmarks GP.
Derek Swingley

Les jointures de table et les requêtes sont beaucoup plus rapides dans l'ancien ArcView 3.2 (avenue) que n'importe quel ArcGIS 8.x à 10. * arcpy / python. essentiellement en raison de la quantité (beaucoup plus) de code dans les produits ArcGIS.
Mapperz

2
@Mapperz Vous avez tout à fait raison. Cependant, le traitement ligne par ligne dans ArcView 3.x est horriblement lent en raison de la surcharge d'interprétation de 10 000 X pour chaque demande (j'ai comparé cela). Quand on peut éviter les boucles - en utilisant des requêtes "de haut niveau" comme les jointures et les requêtes comme vous le suggérez - ArcView 3.x battra le pantalon d'ArcGIS, mais il est plausible que dans un test en tête-à-tête impliquant des boucles explicites sur les enregistrements , l'un ou l'autre pourrait gagner par une marge relativement faible.
whuber

@Whuber @Derek Thar que ce soit.
Nathanus

Réponses:


2

Je ne suis pas nouveau en programmation mais très nouveau en Python alors prenez ça avec un grain de sel ...

copyRecord = arcpy.InsertCursor(outData)

Le curseur d'insertion ne doit-il pas être défini avant la boucle For Next? Il me semble que si le chemin d'accès aux données "out" est stocké dans la variable "outData", il n'a pas besoin d'être réinitialisé à chaque fois que vous itérez. Je pense que cela devrait accélérer considérablement les choses.


Bonne prise. J'essaierai quand je serai de retour au bureau la semaine prochaine.
Nathanus

5

Je suppose que vous utilisez ArcPy ou arcgisscripting vers 9.3. Quoi qu'il en soit, les techniques ici accéléreront votre traitement ... peut-être mieux que vos patrons.

La première chose est d'effectuer des recherches et des insertions avec tout autre support que la mémoire vont ralentir vos processus. Avenue est optimisé pour fonctionner rapidement et utilise une base de code C \ C ++ (corrigez-moi si je me trompe) qui est intrinsèquement plus rapide à IO que la plupart des autres langages. Python est rapide aussi (tout aussi rapide) sauf lorsqu'il y a des frais généraux dans le raccordement aux bibliothèques c pour effectuer des opérations, telles que ArcPy ou arcgisscripting.

Essayez donc ceci en premier:
1. Copiez les tables que vous devez utiliser en mémoire en utilisant les méthodes -

  • gp.CopyFeatures ("Chemin d'accès à featureclass \ FeatureclassName", "'in_memory' \ FeatureclassName") - pour les classes d'entités et;
  • gp.CopyRow ("Chemin d'accès à featureclass \ FeatureTableName", "'in_memory' \ FeatureTableName") - pour les tables dans une classe d'entités ou une table 'in_memory'.

    Cela vous permettra d'utiliser de la mémoire comme un disque RAM et vous fera économiser beaucoup de temps sur le disque. Vous pouvez également créer une classe d'entités ou une table en mémoire en remplaçant le paramètre FeatureDataset par 'in_memory'.

Utilisez autant que possible des conteneurs python. Cela augmentera également la vitesse.

Enfin, l'ordre d'efficacité dans la lecture et l'écriture d'informations pour les formats ESRI est

  1. Shapefile (triste mais vrai)
  2. Géodatabase personnelle
  3. Géodatabase fichier
  4. ArcSDE (même avec une connexion directe, c'est plus lent)

Essayez ces suggestions, car j'essaie de compiler une liste de choses qui fonctionnent ici sur gis.stackexchange.com voir ici


L'option de mémoire semble utile, mais la puissance combinée du tableau que j'interroge contre les horloges à près de 1 Go. Je crois que j'ai assez de RAM pour rendre cela possible, mais la taille de la table risque-t-elle un crash violent? En outre, qu'est-ce qu'un conteneur python?
Nathanus

Je suis surpris que vous placiez gdb personnel plus rapidement que gdb de fichier, car cela est directement inversé par mon expérience. Il serait intéressant d'explorer cela quelque part / heure.
matt wilkie

C'est peut-être le processus avec lequel je travaille actuellement, mais j'ai constaté qu'un fichier gdb est plus lent, mais seulement juste. Je dirais qu'ils sont à égalité, et je choisirais un fichier gdb plutôt que gdb personnel uniquement en raison des limitations de fichiers. Je suis très intéressé à concevoir une référence pour cela. Êtes-vous intéressé à m'aider à définir certains tests?
OptimizePrime

J'ai essayé de mettre le fichier de formes en mémoire, et cela ne semblait pas faire grand chose ... en effet, le script a cessé de fonctionner peu de temps après.
Nathanus

3

Je parie que ce n'est pas qu'Avenue est plus rapide que Python, mais que ArcView3 est plus rapide qu'ArcGIS (à ce que vous essayez de faire).

Étant donné qu'il s'agit essentiellement d'un exercice non spatial, vous voudrez peut-être expérimenter l'accès direct aux tables de la base de données (par exemple, n'utilisez pas arcpy) avec quelque chose comme dbfpy ou odbc (je n'ai pas essayé l'un ou l'autre moi-même). Personnellement, j'ai trouvé que la ligne de commande ogr2ogr de la suite gdal / ogr était plus rapide que les transactions équivalentes dans arcgis. Je n'ai cependant que légèrement plongé dans les capacités de requête OGR, et je n'ai rien construit en utilisant uniquement les liaisons python, donc je ne sais pas si cette vitesse se poursuit.


Le seul hic ici est que j'ajoute des données non spatiales aux données spatiales. IE Je prends le Shapeterrain avec quelques autres et crée un nouvel enregistrement qui contiendra la géométrie et les données non spatiales supplémentaires. Dpfpy et odbc prendront-ils en compte les Shapeschamps en mouvement (et leur géométrie)?
Nathanus

Cela ne fonctionnerait pas avec les fichiers de formes car ils Shapene sont pas stockés dans le .dbf. Théoriquement, cela pourrait fonctionner avec une géodatabase personnelle (.mdb) utilisant odbc mais je me méfie de cette approche, d'autant plus qu'il existe déjà une route éprouvée avec OGR, qui connaît déjà à la fois le fichier de formes et la gdb personnelle.
matt wilkie

1

Ce n'est pas une réponse particulièrement utile pour le moment, mais attendez ArcGIS 10.1. Au sommet esri dev de cette année, on nous a dit que le support du curseur arcpy 10.1 a été complètement réécrit et est beaucoup plus rapide. Au cours de la plénière, il a été réclamé des améliorations de vitesse d'environ 8x.


Merci pour l'information. Quelque chose à espérer, si rien d'autre.
Nathanus
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.