La réponse est les deux pour moi, mais vous êtes le juge pour votre situation ! Lisez la suite pour les critères de décision...
Si vous souhaitez maintenir un grand service d'entités hébergé à partir de données externes, il est préférable d'éviter les réécritures complètes à chaque actualisation, pour deux raisons :
- Les grandes transactions d'écriture peuvent être fragiles
- Les grandes transactions d'écriture peuvent entraîner des temps d'arrêt importants du service
Pour éviter ces deux problèmes, il est préférable de mettre en œuvre une approche CDC (capture des données modifiées) et d'écrire uniquement les deltas dans le service d'entités cible. Ce blog décrira deux façons de procéder :
- Écrire les deltas directement dans le service d'entités cible
- Maintenir une vue de couche d'entités hébergée en la pointant alternativement vers deux services
- Écrire les transactions delta dans le service pas actuellement la source puis échanger celle-ci pour être la source de la vue
Dans la situation habituelle où un delta périodique représente une petite fraction des données, une écriture delta directe peut prendre plusieurs secondes, tandis que pour un échange de source de vue, le temps d'arrêt peut être de l'ordre de millisecondes, mais avec un coût de stockage double.<\/EM> Nous ferons un exemple pratique pour que vous puissiez choisir entre les approches, mais dans tous les cas vous êtes gagnant en utilisant CDC !
Voici mes données métier, environ un million de points d'adresses à Los Angeles, Californie, mises à jour quotidiennement :
Points d'adresses de Los Angeles
Le travail consiste à calculer et appliquer la transaction delta quotidienne (typiquement quelques centaines d'entités) avec un faible temps d'arrêt, et bien que nos modes d'écriture candidats (direct, échange de source de vue) isolent le temps d'arrêt du service du temps de calcul du delta, il est toujours bon de mettre en place toutes les optimisations possibles. Le site open data de la ville supporte le téléchargement CSV, et CSV est un format performant dans les outils ETL spatiaux, ce qui constitue la moitié de l'étape de calcul du delta. L'autre moitié consiste à lire l'état actuel du service/vue d'entités.
Voici mon optimisation pour la lecture du service d'entités, dans LAChangeDetection.fmw (dans le téléchargement du blog) :
Écriture directe après détection des changements
Tandis que le package Esri ArcGIS Connector fournit un lecteur de service d'entités, dans la quête de vitesse j'ai implémenté la lecture du service cible en utilisant plusieurs appels Query concurrents via HTTP. J'ai constaté que le nombre maximal par défaut d'enregistrements par appel (2000) en 4 requêtes concurrentes donnait une performance optimale, environ le double du taux du lecteur packagé. Le transformateur ChangeDetector calcule le delta en quelques secondes une fois qu'il a les données, puis l'écriture du delta prend 3-4 secondes pour un jeu de modifications quotidien typique (si vous inspectez l'espace de travail vous verrez que je l'ai instrumenté avec des transformateurs Emailer pour envoyer des informations horodatées).
Pour ceux qui ne sont pas satisfaits d'un temps d'arrêt de quelques secondes, implémenter l'échange de source de vue est seulement un peu plus complexe, voir LAViewSourceSwap.fmw dans le téléchargement du blog :
Échange de source de vue
Vous verrez une logique dans l'espace de travail pour basculer entre les services "A" et "B" pour la lecture, l'écriture et l'échange de source. Pour cette raison, les changements sont détectés un peu différemment ; la même URL publique accédant aux données d'adresses au format CSV est lue, mais le delta est calculé par rapport à la couche d'entités hébergée qui n'est pas la source actuelle pour la vue de couche hébergée, et le delta est appliqué à cette couche.
Puis la couche mise à jour doit être échangée pour devenir la source de la vue de couche hébergée. Comment ?
La réponse nécessite un peu d'enquête, en inspectant comment ArcGIS gère nativement l'échange de source dans les paramètres des éléments :
Échange de source de vue
Ceci que vous voyez ci-dessus est moi faisant manuellement un échange de source mais avec les outils développeur du navigateur actifs, filtrés pour enregistrer les transactions POST en vue détaillée des requêtes importantes. En cliquant sur l'échange de source j'ai pu voir que le système utilise deux appels, deleteFromDefinition et addToDefinition. Mieux encore, si j'inspecte n'importe quel appel POST je peux voir la charge utile JSON utilisée - ce qui est chanceux car la documentation REST API est un peu difficile pour une personne sans code comme moi 😉.
La charge utile deleteFromDefinition est triviale, mais celle addToDefinition JSON est énorme. Cependant, comme j'ai créé mes services avec les paramètres par défaut que je ne souhaite pas changer, j'ai réduit le JSON aux objets que je pensais valoir la peine de garder, et bien sûr le pointeur requis vers la source désirée. Voici le JSON :
{
"layers": [
{
"currentVersion": 11.5,
"id": 0,
"name": "LosAngelesAddresses",
"type": "Feature Layer",
"cacheMaxAge": 30,
"displayField": "Street_Name",
"description": "",
"copyrightText": "",
"defaultVisibility": true,
"adminLayerInfo": {
"viewLayerDefinition": {
"sourceServiceName": "@Value(_nextSourceName)",
"sourceLayerId": 0,
"sourceLayerFields": "*"
}
},
"geometryType": "esriGeometryPoint",
"objectIdField": "OBJECTID",
"uniqueIdField": {
"name": "OBJECTID",
"isSystemMaintained": true
},
"useStandardizedQueries": true,
"minScale": 0,
"maxScale": 0,
"extent": {
"xmin": -13210040.1828,
"ymin": 3989386.3054,
"xmax": -13153020.1132,
"ymax": 4073637.6182,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
},
"globalIdField": "",
"maxRecordCount": 2000,
"standardMaxRecordCount": 32000,
"standardMaxRecordCountNoGeometry": 32000,
"tileMaxRecordCount": 8000,
"maxRecordCountFactor": 1,
"capabilities": "Query"
}
]
}En production je pourrais éditer le JSON pour ajuster des choses si désiré, comme l'étendue ou le champ affiché, mais c'est probablement un meilleur investissement que de bien concevoir votre couche avant coup.
Une chose clé que j'ai apprise sur cette charge utile est à la ligne 15 où j'injecte un attribut entité dans le JSON au moment de l'exécution, sourceServiceName est une propriété qui identifie le service étant échangé d'entrée, il n'y a aucune référence à son ID d'élément ni à son URL de service. Dans mon cas le nom du service source bascule entre « LosAngelesAddressesA » et « LosAngelesAddressesB » lors des exécutions consécutives. Si une transaction delta ne contient aucune modification alors aucun service l'échange se produit.<\/P>
Nous avons donc maintenant réduit au maximum le temps d'arrêt lors d'une mise à jour du service de fonctionnalités, c'est à vous de décider si la transaction delta de la période moyenne est suffisamment importante (plusieurs milliers de fonctionnalités ?) pour justifier le coût supplémentaire de stockage lié à l'échange de la source de vue et au temps d'arrêt minimum garanti.<\/P>
Bien que je me concentre ici sur la minimisation du temps d'arrêt, et non sur le temps d'exécution total du travail, si quelqu'un est curieux, il faut entre 3 et 5 minutes pour actualiser le million de points avec lesquels je travaille. Je suppose que la variabilité provient des conditions de charge du serveur d'où proviennent et où vont les données.<\/P>
Remerciements :<\/STRONG> J'ai été inspiré pour écrire ce post par mon collègue Esri @SashaLockamy<\/a> qui a exploré ce flux de travail en premier, et à qui je suis reconnaissant, ainsi que par des travaux antérieurs dans un flux de travail connexe où des géodatabases fichier sont republiées, voir la première présentation ici<\/A>.<\/P>