|
| 1 | +# Utiliser Zarr avec OpenFisca Survey Manager |
| 2 | + |
| 3 | +Ce document explique **si et comment** utiliser le backend Zarr pour stocker les enquêtes, et ce qu’il en est de la **compression** et de la **parallélisation** en lecture/écriture. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## 1. Utiliser Zarr avec OpenFisca |
| 8 | + |
| 9 | +### Oui, c’est possible |
| 10 | + |
| 11 | +Le backend **zarr** est disponible dans `openfisca-survey-manager` à condition d’installer la dépendance optionnelle : |
| 12 | + |
| 13 | +```bash |
| 14 | +pip install openfisca-survey-manager[zarr] |
| 15 | +# ou |
| 16 | +pip install openfisca-survey-manager zarr numcodecs |
| 17 | +``` |
| 18 | + |
| 19 | +(pandas 2.x utilise `to_zarr` / `read_zarr` ; le package **zarr** est requis.) |
| 20 | + |
| 21 | +### En ligne de commande (build-collection) |
| 22 | + |
| 23 | +Pour construire une collection en stockant les tables au format Zarr : |
| 24 | + |
| 25 | +```bash |
| 26 | +build-collection -c ma_collection --zarr |
| 27 | +``` |
| 28 | + |
| 29 | +Sans `--zarr`, le format par défaut reste HDF5 (avec avertissement) ou vous pouvez utiliser `--parquet`. |
| 30 | + |
| 31 | +### En Python (fill_store) |
| 32 | + |
| 33 | +```python |
| 34 | +from openfisca_survey_manager.core.dataset import SurveyCollection |
| 35 | + |
| 36 | +col = SurveyCollection.load(collection="ma_collection", config_files_directory="...") |
| 37 | +col.fill_store( |
| 38 | + source_format="sas", # ou csv, parquet, etc. |
| 39 | + store_format="zarr", |
| 40 | +) |
| 41 | +``` |
| 42 | + |
| 43 | +Après cela, chaque survey a un répertoire `{output}/{survey.name}.zarr`, et chaque table est un **groupe zarr** (sous-répertoire) dans ce store. La lecture se fait comme d’habitude avec `survey.get_values(table=..., variables=...)` ; le code utilise automatiquement le backend zarr si `store_format == "zarr"`. |
| 44 | + |
| 45 | +### Vérifier que Zarr est disponible |
| 46 | + |
| 47 | +```python |
| 48 | +from openfisca_survey_manager.io.backends import get_available_backend_names, get_backend |
| 49 | + |
| 50 | +print(get_available_backend_names()) # doit contenir "zarr" si le package est installé |
| 51 | +backend = get_backend("zarr") # lève ValueError si zarr absent |
| 52 | +``` |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## 2. Compression |
| 57 | + |
| 58 | +### Comportement actuel |
| 59 | + |
| 60 | +Dans l’implémentation actuelle, l’écriture Zarr passe par `pandas.DataFrame.to_zarr(path, mode="w")` **sans options de compression explicites**. Zarr/pandas peuvent donc utiliser un comportement par défaut (par ex. compression légère ou aucune selon les versions). |
| 61 | + |
| 62 | +### Ce que Zarr permet en général |
| 63 | + |
| 64 | +Zarr gère la compression **par blocs (chunks)** via **numcodecs**. On peut utiliser par exemple : |
| 65 | + |
| 66 | +- **Blosc** (LZ4, Zstd, Zlib) : bon compromis vitesse / ratio, très utilisé |
| 67 | +- **Zstd** : bon ratio, décompression rapide |
| 68 | +- **LZ4** : très rapide, ratio moindre |
| 69 | +- **Gzip** : standard, plus lent |
| 70 | + |
| 71 | +Ces options se configurent au moment de la **création** du tableau zarr (compressor, chunks). Avec **pandas** : |
| 72 | + |
| 73 | +- `df.to_zarr(path, ...)` peut accepter des arguments supplémentaires passés au store zarr sous-jacent (selon la version de pandas). |
| 74 | +- Pour un contrôle fin (compression, chunking), on peut créer soi‑même un store zarr avec le bon `compressor` puis y écrire les colonnes, ou étendre le backend (voir ci‑dessous). |
| 75 | + |
| 76 | +### Évolution possible dans le survey-manager |
| 77 | + |
| 78 | +On peut faire évoluer le backend Zarr pour accepter des options (compression, chunks) soit : |
| 79 | + |
| 80 | +- via des **kwargs** dans `fill_store(..., store_format="zarr", **zarr_options)` transmis à `to_zarr`, |
| 81 | +- soit via la **config** (manifest ou config.yaml) pour définir un compressor par défaut pour le format zarr. |
| 82 | + |
| 83 | +Aujourd’hui, si vous avez besoin d’une compression précise, vous pouvez : |
| 84 | + |
| 85 | +1. **Enregistrer un backend personnalisé** (`register_backend`) qui appelle `to_zarr` avec le `compressor` (et éventuellement les chunks) de votre choix. |
| 86 | +2. Ou **post‑traiter** les répertoires `.zarr` générés (ré‑écriture avec d’autres options zarr) en dehors du survey-manager. |
| 87 | + |
| 88 | +--- |
| 89 | + |
| 90 | +## 3. Parallélisation lecture / écriture |
| 91 | + |
| 92 | +### Zarr en général |
| 93 | + |
| 94 | +- **Parallélisme par blocs** : Zarr est conçu pour que des **chunks différents** puissent être lus ou écrits en parallèle sans verrou global (chaque chunk est indépendant). |
| 95 | +- **En Python** : le **GIL** limite le gain avec des threads pour la partie compression/décompression ; le parallélisme efficace passe souvent par **multi‑processus** ou des runtimes qui libèrent le GIL (Cython, C extensions utilisées par numcodecs/blosc). |
| 96 | +- **Goulot d’étranglement** : en pratique, la **compression/décompression** peut saturer le CPU (~1 GB/s) alors que le disque ou le réseau peuvent aller plus vite ; des évolutions (batch encode/decode, GPU) sont en cours dans l’écosystème zarr. |
| 97 | + |
| 98 | +### Dans le survey-manager aujourd’hui |
| 99 | + |
| 100 | +- **Écriture** : `fill_store(store_format="zarr")` appelle `to_zarr` pour chaque table, de façon **séquentielle** (une table après l’autre, pas de parallélisation interne exposée). |
| 101 | +- **Lecture** : `get_values()` utilise `read_zarr` pour une table donnée, également de façon **séquentielle** par appel. |
| 102 | + |
| 103 | +Donc **par défaut** : pas de parallélisation multi‑tables ni multi‑chunks exposée dans l’API actuelle. |
| 104 | + |
| 105 | +### Comment paralléliser quand même |
| 106 | + |
| 107 | +1. **Plusieurs tables / plusieurs surveys** |
| 108 | + Vous pouvez paralléliser vous‑même au niveau applicatif : lancer plusieurs processus ou threads qui appellent `fill_store` (ou `get_values`) sur des collections/surveys/tables différents ; chaque processus écrira/lira ses propres fichiers ou groupes zarr sans conflit. |
| 109 | + |
| 110 | +2. **Dask** |
| 111 | + Pour des tableaux zarr, **Dask** (dask.array, ou chargement des zarr en Dask) gère le chargement parallèle par chunks. Cela ne passe pas directement par l’API Survey/SurveyCollection actuelle : il faudrait soit exporter les chemins `.zarr` puis les ouvrir avec Dask, soit ajouter une couche d’intégration (p.ex. une fonction qui retourne un Dask DataFrame à partir d’un survey zarr). |
| 112 | + |
| 113 | +3. **Évolution du backend** |
| 114 | + On pourrait ajouter plus tard un mode « écriture parallèle par table » (threads/processes) ou une option de lecture qui retourne un objet Dask pour exploiter le parallélisme par chunks côté zarr. |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## 4. Résumé pratique |
| 119 | + |
| 120 | +| Question | Réponse | |
| 121 | +|----------|--------| |
| 122 | +| **Utiliser Zarr avec OpenFisca ?** | Oui : `pip install openfisca-survey-manager[zarr]`, puis `build-collection --zarr` ou `fill_store(store_format="zarr")`. | |
| 123 | +| **Compression ?** | Par défaut : comportement zarr/pandas (souvent léger). Pour plus de contrôle : backend personnalisé avec `to_zarr(..., compressor=...)` ou post‑traitement des stores zarr. | |
| 124 | +| **Parallélisation lecture/écriture ?** | Pas exposée dans l’API actuelle (une table à la fois). Parallélisme possible : vous-même sur plusieurs tables/surveys, ou en utilisant Dask sur les chemins zarr générés. | |
| 125 | + |
| 126 | +Si vous voulez, on peut détailler une proposition d’API pour passer des options de compression (et éventuellement de chunking) au backend Zarr dans `fill_store` ou dans la config. |
0 commit comments