Performances d'ArcGISScripting et de grands ensembles de données spatiales

38

J'écris actuellement un script python utilisant le module arcgisscripting pour traiter un ensemble de données assez volumineux (environ 10 000 enregistrements au total) normalisé sur un petit nombre de tables, soit 8 au total. Le processus consiste à créer une fonction basée sur les tuples de coordonnées (x, y) et à créer un graphique (nœuds et lignes) en utilisant les relations des 7 autres tableaux. Le résultat final est une géodatabase personnelle (pgdb / fgdb) avec des ensembles de données spatiales de noeuds et d'arêtes qui représentent visuellement les relations.

Ma tentative initiale consistait à utiliser les requêtes des nouvelles tables de géodatabase et des jeux d'enregistrements SearchCursor pour renseigner des tables de liens (InsertCursor) pour les relations plusieurs à plusieurs. Cela a très bien fonctionné, à l’exception du temps de traitement de 15 à 20 minutes.

En utilisant le module cProfiler en Python, il était évident que le fait de «balayer» une géodatabase personnelle lors de l'exécution des requêtes de recherche pour renseigner les tables de liens avec des demandes de curseurs (curseurs de recherche et d'insertion) était à l'origine de performances épouvantables.

Avec un peu de refactoring, j'ai réussi à obtenir un temps de traitement inférieur à 2,5 minutes. Le compromis consistait en une construction partielle du schéma de la géodatabase dans le code et en limitant les demandes de curseurs arcgisscripting à InsertCursors une fois que toutes les relations avaient été rassemblées.

Ma question est une de performance.

  • Quelles techniques les personnes ont-elles utilisées pour maintenir des temps de calcul raisonnables lors de l'utilisation de grands ensembles de données?
  • Existe-t-il des méthodes recommandées par ESRI que j'ai manquées dans ma recherche d'optimisation?

    Je comprends les frais généraux liés à la création d'un curseur arcgisscripting, en particulier s'il s'agit d'une géodatabase personnelle. Cependant, après une longue recherche de réponses liées à la performance sur ce site et sur Google, j'ai l'impression que la performance n'est pas au premier plan des efforts des utilisateurs. .

  • En tant qu'utilisateur des produits ESRI, attend-on et tolère-t-il ces retards de performances?

MISE À JOUR

Après quelques travaux avec ce produit, j'ai accumulé une liste de techniques d'optimisation qui ont nécessité un processus de conversion d'informations spatiales d'un format propriétaire vers une géodatabase. Ceci a été développé pour la géodatabase personnelle et de fichier. Tidbits:

  1. Lisez vos données et rationalisez-les en mémoire. Cela réduira votre temps de moitié.

  2. Créez des classes d'objets et des tables en mémoire. Utilisez le jeu de clés 'in_memory' pour utiliser votre mémoire en tant que disque virtuel, effectuez vos fonctions là-bas, puis écrivez sur le disque.

  3. Pour écrire sur le disque, utilisez les classes CopyFeatureclass pour les classes d’entités et CopyRow pour les tables.

Ces trois éléments ont nécessité un script convertissant plus de 100 000 fonctionnalités en géodatabase de 30 minutes à 30 - 40 secondes, ce qui inclut les classes de relations. Elles ne doivent pas être utilisées à la légère. La plupart des méthodes ci-dessus utilisent beaucoup de mémoire, ce qui peut entraîner des problèmes si vous ne faites pas attention.

OptimizePrime
la source
1
Avez-vous essayé d'utiliser un format de stockage différent? Comment fonctionne une géodatabase fichier?
Derek Swingley
Une géodatabase fichier est moins performante qu'une géodatabase personnelle. J'ai passé hier à configurer et à configurer une instance ArcSDE afin de tester les performances sur un format d'entreprise. Je vous tiendrai au courant de mes conclusions
OptimizePrime
2
Cela ne vous aide pas pour le moment, mais dans Python, les performances du curseur ont été considérablement améliorées (de l'ordre de l'ordre de grandeur dans la moyenne des cas) avec le nouveau module d'accès aux données.
Jason Scheirer
In_memory utilise un InMemoryWorkspace edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriDataSourcesGDB/… qui, après un nombre arbitraire de lignes, transfère tout dans un ScratchWorkspaceFactory (FileGDB) et s'appuie sur FileGDB pour effectuer tout le travail
Ragi Burhum

Réponses:

56

Bien que cette question ait déjà été répondue, je pensais pouvoir donner un coup de pouce à mes deux cents.

AVERTISSEMENT : J'ai travaillé pour ESRI au sein de l'équipe de GeoDatabase pendant quelques années et j'étais responsable de la maintenance de diverses parties du code de GeoDatabase (versioning, curseurs, sessions d'édition, historique, classes de relations, etc.).

Je pense que la plus grande source de problèmes de performances avec le code ESRI n’est pas la compréhension des implications de l’utilisation d’objets différents, en particulier les "petits" détails des différentes abstractions de GeoDatabase! Alors très souvent, la conversation bascule sur le langage utilisé comme responsable des problèmes de performances. Dans certains cas, cela peut être. Mais pas tout le temps. Commençons par la discussion sur la langue et revenons en arrière.

1.- Le langage de programmation que vous choisissez n'a d'importance que lorsque vous faites quelque chose de compliqué, en boucle serrée. La plupart du temps, ce n'est pas le cas.

Le gros éléphant dans la pièce est qu’au cœur de tout le code ESRI, vous avez ArcObjects - et ArcObjects est écrit en C ++ en utilisant COM . La communication avec ce code a un coût. Cela est vrai pour C #, VB.NET, Python ou tout ce que vous utilisez.

Vous payez un prix lors de l'initialisation de ce code. Cela peut représenter un coût négligeable si vous ne le faites qu'une fois.

Vous payez ensuite un prix pour chaque interaction ultérieure avec ArcObjects.

Personnellement, j’ai tendance à écrire du code pour mes clients en C #, car c’est facile et rapide. Cependant, chaque fois que je souhaite déplacer des données ou effectuer un traitement pour de grandes quantités de données déjà implémentées dans le géotraitement, je viens d'initialiser le sous-système de script et de transmettre mes paramètres. Pourquoi?

  • Il est déjà mis en œuvre. Alors pourquoi réinventer la roue?
  • Cela peut être plus rapide . "Plus rapide que de l'écrire en C #?" Oui! Si je mets en œuvre, par exemple, le chargement de données manuellement, cela signifie que je paie le prix de la commutation de contexte .NET dans une boucle serrée. Chaque GetValue, Insert, ShapeCopy a un coût. Si je passe un seul appel dans GP, l'ensemble du processus de chargement de données aura lieu lors de la mise en œuvre réelle de GP - en C ++ dans l'environnement COM. Je ne paie pas le prix du changement de contexte car il n'y en a pas - et par conséquent, il est plus rapide.

Ah oui, alors la solution consiste à utiliser de nombreuses fonctions de géotraitement. En fait, il faut faire attention.

2. GP est une boîte noire qui copie des données (potentiellement inutilement) autour

C'est une épée à double tranchant. C'est une boîte noire qui fait un peu de magie en interne et crache des résultats - mais ces résultats sont très souvent dupliqués. 100 000 lignes peuvent facilement être converties en 1 000 000 lignes sur disque après avoir exécuté vos données via 9 fonctions différentes. Utiliser uniquement les fonctions GP, c'est comme créer un modèle GP linéaire, et bien ...

3. Le chaînage d'un trop grand nombre de fonctions de gestion de stratégie pour des ensembles de données volumineux est extrêmement inefficace. Un modèle de stratégie de groupe équivaut (potentiellement) à exécuter une requête de manière vraiment très stupide

Maintenant, ne vous méprenez pas. J'aime les modèles GP - cela me évite d'écrire du code tout le temps. Mais je suis également conscient que ce n'est pas le moyen le plus efficace de traiter de grands ensembles de données.

Avez-vous tous entendu parler d'un planificateur de requêtes ? Son travail consiste à examiner l'instruction SQL que vous souhaitez exécuter, à générer un plan d'exécution sous la forme d'un graphe dirigé ressemblant beaucoup à un modèle de stratégie de groupe , à examiner les statistiques stockées dans la base de données et à choisir le plus ordre optimal pour les exécuter . GP les exécute simplement dans l'ordre où vous mettez les choses, car il n'a pas de statistiques pour faire quoi que ce soit plus intelligemment - vous êtes le planificateur de requêtes . Et devine quoi? L'ordre dans lequel vous exécutez les choses dépend beaucoup de votre jeu de données. L’ordre dans lequel vous exécutez les choses peut faire la différence entre les jours et les secondes et c’est à vous de décider.

"Génial", dites-vous, je ne vais pas écrire le scénario moi-même et faire attention à la façon dont j'écris. Mais comprenez-vous les abstractions de GeoDatabase?

4. Ne pas comprendre les abstractions de GeoDatabase peuvent facilement vous mordre

Au lieu de signaler tout ce qui peut éventuellement vous poser un problème, laissez-moi simplement vous signaler quelques erreurs courantes que je vois tout le temps et quelques recommandations.

  • Comprendre la différence entre les curseurs Vrai / Faux pour le recyclage . Ce minuscule indicateur défini sur true peut accélérer les ordres de grandeur d'exécution.
  • Placez votre table dans LoadOnlyMode pour les chargements de données. Pourquoi mettre à jour l'index à chaque insertion?
  • Comprenez que même si IWorkspaceEdit :: StartEditing est identique dans tous les espaces de travail, il s’agit de créatures très différentes sur chaque source de données. Sur une GDB d’entreprise, vous pouvez avoir un contrôle de version ou un support pour les transactions. Sur les fichiers de formes, il devra être mis en œuvre de manière très différente. Comment mettriez-vous en oeuvre Undo / Redo? Avez-vous même besoin de l'activer (oui, cela peut faire une différence dans l'utilisation de la mémoire).
  • Différence entre les opérations de traitement par lots ou les opérations sur une seule ligne. Cas concret GetRow vs GetRows - c'est la différence entre effectuer une requête pour obtenir une ligne ou effectuer une requête pour extraire plusieurs lignes. Une boucle étroite avec un appel à GetRow signifie une performance épouvantable et c'est le premier coupable des problèmes de performance
  • Utilisez UpdateSearchedRows
  • Comprendre la différence entre CreateRow et CreateRowBuffer . Grande différence dans le temps d'exécution des insertions.
  • Comprenez qu'IRow :: Store et IFeature :: Store déclenchent des opérations polymorphes extrêmement lourdes .C'est probablement la raison n ° 2 coupable d'une performance très lente. Il ne s'agit pas simplement d'enregistrer la ligne. Il s'agit de la méthode permettant de vérifier que votre réseau géométrique est correct, que l'éditeur d'ArcMap est averti qu'une ligne a été modifiée, ainsi que toutes les classes de relations ayant un lien avec cette ligne. assurez-vous que la cardinalité est valide, etc. Vous ne devriez pas insérer de nouvelles lignes avec cela, vous devriez utiliser un InsertCursor !
  • Voulez-vous (besoin) de faire ces insertions dans une EditSession? Cela fait une énorme différence si vous faites ou non. Certaines opérations le requièrent (et ralentissent le processus), mais lorsque vous n'en avez pas besoin, ignorez les fonctions annuler / rétablir.
  • Les curseurs sont des ressources coûteuses. Une fois que vous en avez un, vous avez la garantie d'avoir la cohérence et l'isolement et cela a un coût.
  • Cachez d'autres ressources telles que les connexions à la base de données (ne créez pas et ne détruisez pas votre référence Workspace) et les poignées de table (chaque fois que vous ouvrez ou fermez un - plusieurs tables de métadonnées doivent être lues).
  • Placer FeatureClasses à l'intérieur ou à l'extérieur d'un FeatureDataset fait une énorme différence en termes de performances. Ce n'est pas conçu comme une caractéristique organisationnelle!

5. Enfin et surtout ...

Comprendre la différence entre opérations liées aux E / S et aux unités centrales

Honnêtement, j'ai envisagé de développer davantage chacun de ces éléments et peut-être de faire une série d'entrées de blog couvrant chacun de ces sujets, mais la liste d'arriéré de mon agenda ne m'a que giflé et a commencé à crier après moi.

Mes deux centimes.

Ragi Yaser Burhum
la source
5
Merci. J'aurais dû travailler au lieu d'écrire cet article haha
Ragi Yaser Burhum Le
3
+1 Merci beaucoup pour votre contribution, M. Burhum. C'est le type de réponse que je souhaitais recevoir. Si je pouvais voter deux fois je pourrais !! Les utilisateurs d’ArcGISScripting (python) doivent s’en tenir à cette réponse. Bien que les liens reflètent les concepts ArcObjects et .Net, les objets COM sous-jacents sont les mêmes. La compréhension de ces objets vous aidera à mieux planifier le code dans n’importe quel langage. Beaucoup d'informations intéressantes ici !!
OptimizePrime
1
@OptimizePrime C'est un excellent résumé. Et vous avez raison - vous ne pouvez pas ignorer les implications d'ArcObjects si vous souhaitez extraire les performances des produits ESRI
Ragi Yaser Burhum
1
merci, j'ai remplacé magasin () par insérer des curseurs et économisé beaucoup de temps dans mes applications!
Superrache
5

En règle générale, pour les calculs de performances, j'essaie de ne pas utiliser de matériel lié à ESRI. Pour votre exemple, je suggérerais de suivre le processus par étapes, la première étape consistant à lire les données dans des objets Python normaux, à effectuer les calculs, puis la dernière étape à être convertie au format spatial ESRI final. Pour environ 10 000 enregistrements, vous pourriez probablement vous contenter de tout stocker en mémoire pour le traitement, ce qui donnerait un gain de performance certain.

Anthony -GISCOE-
la source
Merci pour votre réponse. C'est une bonne suggestion. J'ai commencé à refactoriser le code pour effectuer les procédures requises avant d'utiliser arcgisscripting. Après avoir utilisé le logiciel depuis ses jours ArcInfo, je trouve frustrant que les performances du processeur et des capacités matérielles augmentent, les performances d'ArcGIS Map / Info / Editor XX stagnent. Peut-être que l'introduction des GPU pourrait améliorer les choses. Bien qu'un bon refactor de la base de code ESRI puisse aussi aider
OptimizePrime le
1

En fonction du matériel dont vous disposez, vous pouvez également considérer l'option affichée dans l'exemple de géocodeur ESRI; cela vous donne un cadre pour décomposer un grand ensemble de données et exécuter plusieurs instances de python pour vous donner une approche presque multithread. J'ai vu des performances de géocodage aller de 180 000 à l'heure dans une seule instance Python à plus d'un million, grâce à la rotation de 8 processus parallèles sur ma machine.

J'ai constaté que le fait de m'éloigner autant que possible et de conserver les données dans la base de données, ainsi que le travail fonctionnel dans mes tables et le simple fait d'utiliser un SIG explicite dans le domaine ESRI entraînaient des augmentations majeures des performances.

DEWright
la source
Ce sont d'excellentes idées. J'ai la possibilité d'insérer des processus dans ce script, mais je constate que mes goulots d'étranglement initialisent les bibliothèques COM et les E / S de la géodatabase. En ce qui concerne les E / S, j'ai réduit le besoin à une seule écriture. Si je consacre plus de temps à l'optimisation, mon patron va avoir une crise;) Je laisse donc filer la dernière compression de la performance s'il en demande plus. Pour le moment, je traite 60 000 fonctionnalités par minute.
OptimizePrime
0

Vous trouverez peut-être ces articles intéressants dans le contexte d'optimisation, mais pour les données raster et dans l'ensemble:

Compilation de scripts Python utilisant les outils de géotraitement ArcGIS?

Temps de traitement à l'aide des outils de la boîte à outils ArcGIS Hydrology dans un script Python autonome par rapport à ArcCatalog?

le paramètre gp.scratchworkspace a fait une grande différence pour moi dans le code python que j'ai écrit pour faire des délimitations de bassins versants.

Pourriez-vous poster des exemples de code illustrant les numéros 1 et 2 dans votre MISE À JOUR à votre question d'origine? Je serais intéressé de voir la mécanique de cela (bien que je suppose que vous traitez avec des données de classe d'entités seulement ici)

merci, Tom

turkishgold
la source