POC (Proof of Concept) - Outil de conversion de géodatabase ESRI (.gdb) vers Spatialite (.sqlite) avec préservation des métadonnées et optimisations de performance.
⚠️ Note : Ce projet est un prototype de démonstration. Il peut contenir des bugs et des limitations. Utilisez-le à vos propres risques.
Note : Cette section décrit les fonctionnalités implémentées dans ce POC. Certaines peuvent avoir des limitations ou nécessiter des améliorations.
- Conversion de géodatabase ESRI vers Spatialite
- Préservation des couches, géométries et attributs
- Support de la conversion d'une couche spécifique ou de toutes les couches
- Validation basique des entrées
- Alias de champs : Conservation des noms alternatifs des colonnes (expérimental)
- Domaines codés : Préservation des alias de valeurs via parsing XML (expérimental)
- Clés primaires : Recréation basique des contraintes de clés primaires
- Triggers : Support limité (les triggers ESRI ne sont généralement pas accessibles via GDAL)
- Index spatiaux : Création automatique (toujours activés)
- Mode optimisé par défaut : Optimisations modérées (sécurité + performance)
- Mode fast-mode : Optimisations agressives (expérimental, risque de corruption)
- Multi-threading : Support basique pour conversion parallèle
- Logs avec horodatage et niveaux (INFO, DEBUG, WARNING, ERROR)
- Barres de progression avec tqdm (globale et par couche)
- Statistiques de conversion (temps, taille, succès/échecs)
- Monitoring basique des processus ogr2ogr
GDAL (Geospatial Data Abstraction Library) est requis pour la conversion.
sudo apt-get update
sudo apt-get install python3-gdal gdal-binbrew install gdalTélécharger les binaires depuis OSGeo4W ou utiliser conda:
conda install -c conda-forge gdalpip install -r requirements.txtLes dépendances incluent :
gdal: Bibliothèque géospatialetqdm: Barres de progression
python gdb_to_spatialite.py Role_2024.gdb output.sqliteCette commande convertit toutes les couches avec les optimisations par défaut et la préservation des métadonnées (si disponibles).
# Conversion de toutes les couches
python gdb_to_spatialite.py Role_2024.gdb output.sqlite
# Conversion avec écrasement du fichier existant
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --overwritepython gdb_to_spatialite.py Role_2024.gdb output.sqlite --layer "NomCouche"# Conversion avec 4 threads en parallèle
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --workers 4
# Note: Pour plusieurs couches vers un seul fichier SQLite,
# le mode séquentiel est automatiquement forcé (max_workers=1)# Mode performance maximale (sécurité réduite)
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --fast-mode
# Fast-mode avec multi-threading
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --fast-mode --workers 4--fast-mode désactive certaines protections SQLite (synchronous=OFF, journal_mode=OFF) pour maximiser les performances. À utiliser uniquement si vous avez des sauvegardes et que la perte de données n'est pas critique.
# Désactiver toutes les métadonnées
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --no-metadata
# Préserver seulement les alias, pas les domaines
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --skip-domains
# Préserver seulement les domaines, pas les alias
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --skip-aliases
# Ignorer les clés primaires
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --skip-primary-keyspython gdb_to_spatialite.py Role_2024.gdb output.sqlite --list-layersSortie :
Couches disponibles dans Role_2024.gdb:
1. B05EX1_B05V_REPAR_FISC (1598005 entités)
2. rol_unite_p (3711045 entités)
3. B05EX1_B05V_ADR_UNITE_EVALN (3788405 entités)
4. B05EX1_B05V_UNITE_EVALN (3711218 entités)
python gdb_to_spatialite.py Role_2024.gdb output.sqlite --quietpython gdb_to_spatialite.py Role_2024.gdb output.sqlite --no-ogr2ogrNote : ogr2ogr est recommandé pour de meilleures performances et fiabilité.
gdb_path: Chemin vers le dossier .gdb (géodatabase ESRI) - obligatoireoutput_path: Chemin vers le fichier Spatialite de sortie (.sqlite ou .db) - obligatoire
| Option | Description |
|---|---|
--layer NOM |
Convertir uniquement la couche spécifiée (par défaut: toutes les couches) |
--overwrite |
Écraser le fichier de sortie s'il existe déjà |
--workers N |
Nombre de threads pour la conversion parallèle (défaut: 1, séquentiel) |
--no-ogr2ogr |
Forcer l'utilisation de l'API Python au lieu d'ogr2ogr |
| Option | Description |
|---|---|
--no-metadata |
Désactiver toutes les métadonnées (alias, domaines, clés primaires, triggers) |
--skip-aliases |
Ne pas préserver les alias de champs |
--skip-domains |
Ne pas préserver les domaines codés (alias de valeurs) |
--skip-primary-keys |
Ne pas recréer les clés primaires |
--skip-triggers |
Ne pas recréer les triggers |
| Option | Description |
|---|---|
--fast-mode |
Activer les optimisations agressives (sécurité réduite, performance maximale) |
| Option | Description |
|---|---|
--list-layers |
Lister les couches disponibles dans la géodatabase et quitter |
--quiet |
Mode silencieux (moins de logs détaillés) |
POC : Cette fonctionnalité est expérimentale. L'extraction des métadonnées peut ne pas fonctionner pour toutes les géodatabases et peut avoir des limitations.
L'outil tente de préserver les métadonnées disponibles dans la géodatabase ESRI source.
Les alias de champs sont extraits depuis la géodatabase et stockés dans la table metadata_field_aliases.
Structure :
CREATE TABLE metadata_field_aliases (
table_name TEXT NOT NULL,
field_name TEXT NOT NULL,
alias TEXT NOT NULL,
PRIMARY KEY (table_name, field_name)
)Exemple d'utilisation :
SELECT alias FROM metadata_field_aliases
WHERE table_name = 'b05ex1_b05v_repar_fisc'
AND field_name = 'anrole';
-- Résultat: "ANNEE DU ROLE"Les domaines codés (associations code → description) sont extraits depuis le catalogue XML de la géodatabase et stockés dans la table metadata_domain_values.
Structure :
CREATE TABLE metadata_domain_values (
table_name TEXT NOT NULL,
field_name TEXT NOT NULL,
code INTEGER NOT NULL,
description TEXT NOT NULL,
PRIMARY KEY (table_name, field_name, code)
)Exemple d'utilisation :
SELECT code, description FROM metadata_domain_values
WHERE table_name = 'b05ex1_b05v_repar_fisc'
AND field_name = 'rl0504e'
ORDER BY code;Note (POC) : L'extraction des domaines utilise le parsing automatique du fichier catalogue XML de la géodatabase (a00000004.gdbtable ou similaire). Cette méthode est expérimentale et peut ne pas fonctionner pour toutes les structures de géodatabase.
Les clés primaires sont détectées et recréées comme index uniques dans Spatialite.
Exemple :
-- Index unique créé automatiquement
CREATE UNIQUE INDEX pk_table_name_field1_field2
ON "table_name" ("field1", "field2");Les triggers SQL sont préservés si disponibles (limitation : les triggers ESRI ne sont généralement pas accessibles via GDAL/OGR).
Par défaut, l'outil applique des optimisations équilibrées entre sécurité et performance :
-
SQLite PRAGMA :
synchronous = NORMAL: Équilibre sécurité/performancejournal_mode = WAL: Write-Ahead Logging (plus rapide que DELETE)cache_size = 256MB: Cache modérétemp_store = MEMORY: Tables temporaires en mémoire
-
Index spatiaux : Créés automatiquement pour toutes les couches avec géométrie (MUST HAVE)
-
Optimisations ogr2ogr :
SPATIAL_INDEX=YES: Création immédiate des index spatiauxINIT_WITH_EPSG=NO: Évite la réinitialisation si déjà fait
Le mode --fast-mode active des optimisations agressives pour maximiser les performances :
-
SQLite PRAGMA :
synchronous = OFF: Désactive complètement la synchronisationjournal_mode = OFF: Désactive le journal (risque de corruption en cas de crash)cache_size = 512MB: Cache maximaltemp_store = MEMORY: Tables temporaires en mémoire
-
Analyse SQLite : Exécution automatique de
ANALYZEpour optimiser les statistiques
- Vous avez des sauvegardes régulières
- La perte de données n'est pas critique
- Vous recherchez des performances maximales
Les index spatiaux sont toujours créés automatiquement pour toutes les couches contenant des géométries. Ils ne peuvent pas être désactivés car ils sont essentiels pour les performances des requêtes spatiales.
Les index spatiaux sont créés via l'option ogr2ogr SPATIAL_INDEX=YES et sont visibles dans la table geometry_columns avec spatial_index_enabled = 1.
- Réutilisation de la datasource GDAL : La datasource est mise en cache pour éviter les ouvertures/fermetures répétées lors de l'extraction des métadonnées
- Polling adaptatif : Le monitoring des processus utilise un polling adaptatif (100ms → 1s) pour réduire la latence
- Cache des domaines : Les domaines sont chargés une seule fois depuis le catalogue XML et mis en cache
POC : Cette section décrit l'architecture cible du projet. L'implémentation peut avoir des limitations.
Le script tente de respecter les principes SOLID et les bonnes pratiques de développement :
-
Single Responsibility : Chaque classe a une responsabilité unique
GDBToSpatialiteConverter: Orchestration de la conversionGDBMetadataExtractor: Extraction des métadonnées depuis la GDBSpatialiteMetadataApplier: Application des métadonnées dans SpatialiteProgressLogger: Gestion des logs et progression
-
Open/Closed : Extensible sans modification grâce à l'interface CLI et l'injection de dépendances
-
Dependency Inversion : Utilise les abstractions GDAL/OGR plutôt que des implémentations spécifiques
GDBToSpatialiteConverter: Classe principale orchestrant la conversionGDBMetadataExtractor: Extraction des métadonnées (alias, domaines, clés primaires, triggers)SpatialiteMetadataApplier: Application des métadonnées dans la base SpatialiteProgressLogger: Logging avec niveaux et formatageProcessMonitor: Monitoring non-bloquant des processus ogr2ogr
2025-11-05 23:54:50 - INFO - ============================================================
2025-11-05 23:54:50 - INFO - Début de la conversion GDB vers Spatialite
2025-11-05 23:54:50 - INFO - ============================================================
2025-11-05 23:54:50 - INFO - Source: Role_2024.gdb
2025-11-05 23:54:50 - INFO - Destination: output.sqlite
2025-11-05 23:54:50 - INFO - ogr2ogr disponible: GDAL 3.10.2, released 2025/02/11
2025-11-05 23:54:50 - INFO - Nombre de couches trouvées: 4
2025-11-05 23:54:50 - INFO - Couches à convertir: 1
2025-11-05 23:54:50 - INFO - 1. B05EX1_B05V_REPAR_FISC: 1598005 entités
2025-11-05 23:54:50 - INFO - Conversion avec ogr2ogr (max_workers=1)
2025-11-05 23:54:50 - INFO - [1/1] Conversion de 'B05EX1_B05V_REPAR_FISC'...
Conversion: 100%|██████████| 1/1 [00:17<00:00, 17.45s/couche]
2025-11-05 23:55:07 - INFO - ✓ Couche 'B05EX1_B05V_REPAR_FISC' convertie avec succès
2025-11-05 23:55:07 - INFO - Application des métadonnées pour 'B05EX1_B05V_REPAR_FISC'...
2025-11-05 23:55:07 - INFO - ✓ 19 alias de champs appliqués pour 'b05ex1_b05v_repar_fisc'
2025-11-05 23:55:07 - INFO - ✓ 12 valeurs de domaine appliquées pour 'b05ex1_b05v_repar_fisc' (4 champs)
2025-11-05 23:55:07 - INFO - ✓ Métadonnées appliquées pour 'B05EX1_B05V_REPAR_FISC'
2025-11-05 23:55:07 - INFO - ============================================================
2025-11-05 23:55:07 - INFO - Résumé de la conversion
2025-11-05 23:55:07 - INFO - ============================================================
2025-11-05 23:55:07 - INFO - Temps total: 17s
2025-11-05 23:55:07 - INFO - Couches réussies: 1/1
2025-11-05 23:55:07 - INFO - ✓ Fichier créé: output.sqlite (135.16 MB)
2025-11-05 23:55:07 - INFO - ✓ Base SQLite optimisée pour les performances
Solution :
- Vérifiez que GDAL est correctement installé :
ogr2ogr --version - Vérifiez que le driver OpenFileGDB est compilé dans votre version de GDAL
- Sur Ubuntu/Debian, installez
gdal-binetpython3-gdal
Solutions :
- Vérifiez que le chemin vers le .gdb est correct et absolu
- Vérifiez que le dossier .gdb n'est pas corrompu
- Vérifiez les permissions d'accès au dossier
- Assurez-vous que la géodatabase n'est pas verrouillée par un autre processus
Solutions :
- Le script essaie d'initialiser Spatialite automatiquement
- Si cela échoue, vous pouvez l'initialiser manuellement avec
spatialite_guiou un client SQLite :SELECT load_extension('mod_spatialite'); SELECT InitSpatialMetadata(1);
Explication : Pour plusieurs couches vers un seul fichier SQLite, le mode séquentiel est automatiquement forcé pour éviter les conflits de verrous SQLite. C'est normal et nécessaire.
Optimisations possibles :
- Utilisez
--fast-modepour des optimisations agressives (attention aux risques) - Augmentez
--workerssi vous convertissez plusieurs couches vers des fichiers séparés - Vérifiez que les index spatiaux sont bien créés (toujours activés par défaut)
- Assurez-vous d'avoir assez de RAM (cache SQLite)
Vérifications :
- Vérifiez que les métadonnées existent dans la géodatabase source
- Consultez les tables
metadata_field_aliasesetmetadata_domain_valuesdans la base Spatialite - Activez les logs détaillés (sans
--quiet) pour voir les messages d'extraction - Les domaines sont extraits depuis le catalogue XML de la GDB (
a00000004.gdbtable)
- Documentation GDAL
- Documentation Spatialite
- Format Geodatabase ESRI
- Architecture des géodatabases ESRI
- spatialite_gui : Interface graphique pour Spatialite
- QGIS : Logiciel SIG supportant les géodatabases ESRI et Spatialite
- ogr2ogr : Outil en ligne de commande pour conversions de formats
Ce projet est distribué sous la licence Unlicense (domaine public).
Voir le fichier LICENSE pour plus de détails.
Ce projet utilise les bibliothèques suivantes :
- GDAL/OGR : Licence MIT (source)
- SQLite : Domaine public (source)
- Spatialite : MPL/GPL/LGPL (source)
- tqdm : Licence MIT (source)
La licence Unlicense a été choisie car :
- ✅ Maximum de liberté : Domaine public, aucune restriction d'utilisation
- ✅ Compatible : Compatible avec toutes les licences (MIT, GPL, MPL, etc.)
- ✅ Simple : Aucune attribution requise (bien que recommandée)
- ✅ Idéal pour un POC : Permet la réutilisation totale sans contrainte
- ✅ Aligné avec SQLite : Même philosophie que SQLite (domaine public)
Note : L'Unlicense place le code dans le domaine public. Certaines juridictions peuvent avoir des règles différentes concernant le "domaine public" par déclaration.
GDB2SQL - POC de conversion de géodatabases ESRI vers Spatialite.
Auteur : Simon Bédard
Contact : software@servicesforestiers.tech
Licence : Unlicense (Domaine public)
⚠️ Avertissement : Ce projet est un prototype de démonstration. Il peut contenir des bugs, des limitations et des fonctionnalités non testées. Utilisez-le à vos propres risques et vérifiez toujours les résultats de conversion.