From 2f1af803deb41a037ea83fb435fddf80e160d38f Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Sun, 19 Nov 2023 15:20:56 +0100 Subject: [PATCH 01/92] =?UTF-8?q?Premi=C3=A8re=20esquisse=20de=20fiche=20s?= =?UTF-8?q?ur=20arrow=20et=20duckdb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 75 ++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd new file mode 100644 index 00000000..904e0321 --- /dev/null +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -0,0 +1,75 @@ +# Manipuler des données avec `arrow` et `duckdb` {#arrow-duckdb} + + +## Tâches concernées et recommandations + +L'utilisateur souhaite XXXXXX. + +::: {.callout-recommandation .icon} + +XXXXXX +::: + +::: {.callout-remarque .icon} +Les données sont volumineuses + +Il y a un coût d'entrée. +::: + +::: {.callout-conseil .icon} +Il est fortement recommandé de lire les fiches Parquet et dplyr avant de lire cette fiche. +::: + + +## Présentation des _packages_ `arrow` et `duckdb` + +### Qu'est-ce qu'`arrow`? + +Apache `arrow` est un projet _open-source_ qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Un point important à retenir est donc que __`arrow` n'est pas un outil spécifique à `R`__, et il faut bien distinguer le projet `arrow` du _package_ `R` `arrow`. Ce _package_ propose simplement une interface qui permet d'utiliser le projet `arrow` avec `R`, et il existe d'autres interfaces pour se servir d'`arrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. + + +### Spécificités de `arrow` + +Le projet `arrow` présente cinq spécificités: + +- Représentation des données en mémoire: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de _columnar format_). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, `arrow` va accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. + +- Utilisation avec Parquet : `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. + +- Traitement de données volumineuses: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). + +- Interopérabilité : `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. + +- _Lazy Evaluation_: `arrow` prend en charge la _lazy evaluation_ (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. + +### A quoi sert le _package_ `arrow`? + +Du point de vue d'un statisticien utilisant `R`, le _package_ `arrow` permet de faire trois choses: + +- Importer des données (exemples: fichiers CSV, fichiers Parquet, stockage S3) et les stocker en mémoire vive en format `arrow`; +- Manipuler des données en format `arrow` selon la syntaxe `dplyr` ou en SQL (grâce à `duckdb`); +- Stocker des données en format Parquet. + + +## Comment utiliser `arrow`? + +- la différence entre grammaire de traitement et moteur d'exécution; +- lazy evaluation avec arrow; +- La différence compute()/collect(); +- la différence entre charger les données avec `read_parquet` et `open_dataset`; +- La liste des fonctions connues par Acero; +- les fonctions définies par l'utilisateur (utilisation avancée) +- il est essentiel de rester en ArrowTable si on manipule des données volumineuses; +- l'interface arrow/duckdb +- l'utilisation de `duckdb` en plain SQL ou via `dbplyr`; + + + +### Introduction + +## Pour en savoir plus {#RessourcesArrow} + +- la doc [`arrow`](xxx) ; +- la doc [`duckdb`](xxx) ; +- diverses ressources à citer. + + From 18b5ef0905722f0469806331b1809271b5a3c78d Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 09:12:43 +0100 Subject: [PATCH 02/92] Ajouter les avantages d'arrow --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 904e0321..d1fc6599 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -50,6 +50,15 @@ Du point de vue d'un statisticien utilisant `R`, le _package_ `arrow` permet de - Stocker des données en format Parquet. +### Quels sont les avantages d'`arrow`? + +En pratique, le _package_ `arrow` présente trois avantages: + +- __Performances élevées__: `arrow` est très efficace et très rapide pour la manipulation de données tabulaires (nettement plus performant que `dplyr` par exemple); +- __Usage réduit des ressources__: `arrow` est conçu pour ne charger en mémoire que le minimum de données. Cela permet de réduire considérablement les besoins en mémoire, même lorsque les données sont volumineuses; +- __Facilité d'apprentissage__ grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. + + ## Comment utiliser `arrow`? - la différence entre grammaire de traitement et moteur d'exécution; From de639d0667dd9e9bf9b13ab9bbd7c71e3bfacc0f Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 09:14:57 +0100 Subject: [PATCH 03/92] Ajouter la fiche arrow duckdb dans le quarto book --- _quarto.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/_quarto.yml b/_quarto.yml index 82919af4..4de80a3d 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -64,6 +64,7 @@ book: chapters: - 03_Fiches_thematiques/Fiche_tidyverse.qmd - 03_Fiches_thematiques/Fiche_datatable.qmd + - 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd - 03_Fiches_thematiques/Fiche_joindre_donnees.qmd - 03_Fiches_thematiques/Fiche_donnees_textuelles.qmd - 03_Fiches_thematiques/Fiche_survey.qmd From 962da933f804c82d75aac1d1716fdcd941735b2c Mon Sep 17 00:00:00 2001 From: Lino Galiana Date: Mon, 20 Nov 2023 09:31:06 +0100 Subject: [PATCH 04/92] upgrade npm --- .github/workflows/bookdown-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bookdown-test.yaml b/.github/workflows/bookdown-test.yaml index 940f4228..fd8f7963 100644 --- a/.github/workflows/bookdown-test.yaml +++ b/.github/workflows/bookdown-test.yaml @@ -39,7 +39,7 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '18' - name: Deploy to Netlify if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} # NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID added in the repo's secrets From f4eef8d0b133354c4402e435a8a7646efd99b65f Mon Sep 17 00:00:00 2001 From: Lino Galiana Date: Mon, 20 Nov 2023 09:31:31 +0100 Subject: [PATCH 05/92] upgrade npm prod --- .github/workflows/prod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yaml b/.github/workflows/prod.yaml index 6b7bbd90..87fe8470 100644 --- a/.github/workflows/prod.yaml +++ b/.github/workflows/prod.yaml @@ -75,7 +75,7 @@ jobs: if: ${{ github.repository == 'inseefrlab/utilitr' }} uses: actions/setup-node@v2 with: - node-version: '14' + node-version: '18' - name: Deploy to Netlify if: ${{ github.repository == 'inseefrlab/utilitr' }} # NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID added in the repo's secrets From 8d5e0a2492e7bfc9f96db7d49eb83e6ab9e9d4f3 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 09:52:39 +0100 Subject: [PATCH 06/92] Ajouter des liens --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index d1fc6599..34a70a69 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -16,7 +16,7 @@ Il y a un coût d'entrée. ::: ::: {.callout-conseil .icon} -Il est fortement recommandé de lire les fiches Parquet et dplyr avant de lire cette fiche. +Il est fortement conseillé de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. ::: From 1ac9b4bce236e0d3909f7aaeacc60d4d56c8ee0e Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 09:58:09 +0100 Subject: [PATCH 07/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20des=20recommandati?= =?UTF-8?q?ons=20tidyverse=20et=20data.table=20pour=20prendre=20en=20compt?= =?UTF-8?q?e=20arrow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_datatable.qmd | 2 +- 03_Fiches_thematiques/Fiche_tidyverse.qmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_datatable.qmd b/03_Fiches_thematiques/Fiche_datatable.qmd index add01356..3269ac2c 100644 --- a/03_Fiches_thematiques/Fiche_datatable.qmd +++ b/03_Fiches_thematiques/Fiche_datatable.qmd @@ -6,7 +6,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} * Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser le package `dplyr` ; -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser le package `data.table` qui fait l'objet de la présente fiche. +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` traités par la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). ::: ::: {.callout-remarque .icon} diff --git a/03_Fiches_thematiques/Fiche_tidyverse.qmd b/03_Fiches_thematiques/Fiche_tidyverse.qmd index b2c32deb..1e45f4cf 100644 --- a/03_Fiches_thematiques/Fiche_tidyverse.qmd +++ b/03_Fiches_thematiques/Fiche_tidyverse.qmd @@ -8,7 +8,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} * Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui font l'objet de la présente fiche ; -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable). +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` traités par la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). ::: ::: {.callout-remarque .icon} From 70b8ea2692093d209fb226e8e2b1b85dc405c3dd Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 10:52:58 +0100 Subject: [PATCH 08/92] =?UTF-8?q?Compl=C3=A9ments=20sur=20les=20recommanda?= =?UTF-8?q?tions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 14 ++++++-------- 03_Fiches_thematiques/Fiche_datatable.qmd | 4 ++-- 03_Fiches_thematiques/Fiche_tidyverse.qmd | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 34a70a69..2d989992 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -3,20 +3,18 @@ ## Tâches concernées et recommandations -L'utilisateur souhaite XXXXXX. +L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-recommandation .icon} +* Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` qui font l'objet de la présente fiche. -XXXXXX +- Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les _packages_ `arrow` et `duckdb` sont en cours de développement. ::: ::: {.callout-remarque .icon} -Les données sont volumineuses + -Il y a un coût d'entrée. -::: - -::: {.callout-conseil .icon} -Il est fortement conseillé de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. +- Apprendre à bien utiliser `arrow` n'est ni rapide ni simple, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. Il est donc complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`. +- Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. ::: diff --git a/03_Fiches_thematiques/Fiche_datatable.qmd b/03_Fiches_thematiques/Fiche_datatable.qmd index 3269ac2c..96a95a0f 100644 --- a/03_Fiches_thematiques/Fiche_datatable.qmd +++ b/03_Fiches_thematiques/Fiche_datatable.qmd @@ -5,8 +5,8 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-recommandation .icon} -* Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser le package `dplyr` ; -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` traités par la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). +* Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la présente fiche, soit les _packages_ `arrow` et `duckdb` présentés dans la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). ::: ::: {.callout-remarque .icon} diff --git a/03_Fiches_thematiques/Fiche_tidyverse.qmd b/03_Fiches_thematiques/Fiche_tidyverse.qmd index 1e45f4cf..f274f620 100644 --- a/03_Fiches_thematiques/Fiche_tidyverse.qmd +++ b/03_Fiches_thematiques/Fiche_tidyverse.qmd @@ -8,7 +8,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} * Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui font l'objet de la présente fiche ; -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` traités par la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` présenté dans la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` présentés dans la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). ::: ::: {.callout-remarque .icon} From d8d6af32a0075fcbfd7fe0bd18ca396b6aad6ea5 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 16:17:41 +0100 Subject: [PATCH 09/92] Expliquer ce qu'est un Arrow Table --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 59 +++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 2d989992..bdbd9580 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -13,8 +13,11 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: ::: {.callout-remarque .icon} -- Apprendre à bien utiliser `arrow` n'est ni rapide ni simple, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. Il est donc complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`. +Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. + - Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. +- Il est complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`, il ne faut donc pas se décourager. +- Il ne faut pas hésiter à demander de l'aide à des collègues, ou à poser des questions sur les salons Tchap adaptés (le salon Langage `R` par exemple). ::: @@ -59,6 +62,60 @@ En pratique, le _package_ `arrow` présente trois avantages: ## Comment utiliser `arrow`? +Pour utiliser `arrow`, il faut commencer par charger le _package_. En pratique, `arrow` s'utilise presque toujours avec `dplyr`, il est donc préférable de prendre l'habitude de charger les deux _packages_ ensemble. + +```{r} +library(arrow) +library(dplyr) +``` + +### Le `data.frame` version `arrow`: le `Arrow Table` + +**Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. + +Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part et en `Arrow Table` d'autre part. + +```{r} +# Charger les données et les convertir en tibble +bpe_ens_2018_tbl <- doremifasolData::bpe_ens_2018 |> as_tibble() + +# Charger les données et les convertir en Arrow Table +bpe_ens_2018_arrow <- doremifasolData::bpe_ens_2018 |> as_arrow_table() +``` + +Première différence: alors que les `data.frames` et les `tibbles` apparaissent dans la rubrique `Data` de l'environnement `RStudio` (cadre rouge dans la capture d'écran), les objets `Arrow Table` apparaissent dans la rubrique `Values` (cadre blanc). + + +![](../pics/arrow/diff_environnement.png) + +Deuxième différence: alors que l'appel à un `data.frame` ou `tibble` en affiche les premières lignes, l'appel à un `Arrow Table` affiche uniquement des métadonnées (nombre de lignes et de colonnes, nom et type des colonnes). + +```{r} +# Affichage d'un tibble +bpe_ens_2018_tbl +``` + +```{r} +# Affichage d'un Arrow Table +bpe_ens_2018_arrow +``` + +Troisième différence: alors qu'il est possible d'afficher le contenu d'un `data.frame` ou d'un `tibble` en cliquant sur son nom dans la rubrique `Data` de l'environnement ou en utilisant la fonction `View()`, il n'est pas possible d'afficher directement le contenu d'un `Arrow Table`. Pour afficher le contenu d'un `Arrow Table`, il faut d'abord convertir le `Arrow Table` en `tibble` avec la fonction `collect()`. + + +::: {.callout-conseil .icon} +Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` pose de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. __Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.__ Voici un exemple de code qui le fait: + +```{r, eval=FALSE} +# Extraire les 1000 premières lignes du Arrow Table et les convertir en tibble +extrait_bpe <- bpe_ens_2018_arrow |> slice_head(n = 1000) |> collect() +View(extrait_bpe) +``` +::: + + + + - la différence entre grammaire de traitement et moteur d'exécution; - lazy evaluation avec arrow; - La différence compute()/collect(); From b8de9aee6fe35ab7df341db0aa641dedfdf2e116 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Mon, 20 Nov 2023 16:18:14 +0100 Subject: [PATCH 10/92] =?UTF-8?q?Ajouter=20la=20capture=20d'=C3=A9cran?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pics/arrow/diff_environnement.png | Bin 0 -> 20133 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pics/arrow/diff_environnement.png diff --git a/pics/arrow/diff_environnement.png b/pics/arrow/diff_environnement.png new file mode 100644 index 0000000000000000000000000000000000000000..cebc31f37de9d51fda5248b3424787103754e4e9 GIT binary patch literal 20133 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 Date: Tue, 21 Nov 2023 09:35:38 +0100 Subject: [PATCH 11/92] Coquille --- 03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd index 7e618c15..42579fcd 100644 --- a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd +++ b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd @@ -129,7 +129,7 @@ Partitionner un fichier revient à le "découper" selon une clé de partitionnem ::: {.callout-conseil .icon} - **Il est important de bien choisir les variables de partitionnement** d'un fichier **Parquet**. Il faut choisir des variables faciles à comprendre et qui soient cohérentes avec l'usage des données (année, département, secteur...). En effet, un partitionnement bien construit induit par la suite des gains d'efficacité sur les traitements et facilite la maintenance du fichier sur le long terme. - **Il est inutile de partitionner des données de petite taille**. Si les données dépassent quelques millions d'observations et/ou si leur taille en CSV dépasse quelques giga-octets, il est utile de partitionner. -- **Il ne faut pas partitionner les données en trop de fichiers**. En pratique, il est rare d'avoir besoin de plus qu'une ou deux variables de partitionnement. +- **Il ne faut pas partitionner les données en trop de fichiers**. En pratique, il est rare d'avoir besoin de plus d'une ou deux variables de partitionnement. ::: Pour créer des fichiers **Parquet** partitionnés, il faut utiliser la fonction [`write_dataset()`](https://arrow.apache.org/docs/r/reference/write_dataset.html) du _package_ `arrow`. Voici ce que ça donne sur le fichier de la BPE : From 13558ddcb29179bca9f3da5a513d94474fef0d5f Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Tue, 21 Nov 2023 15:52:23 +0100 Subject: [PATCH 12/92] Ticks --- 03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd index 42579fcd..c650ec52 100644 --- a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd +++ b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd @@ -182,7 +182,7 @@ donnees <- arrow::read_parquet( ) ``` -Dans les trois cas, le résultat obtenu est un objet directement utilisable dans R. +Dans les trois cas, le résultat obtenu est un objet directement utilisable dans `R`. ### Cas des données volumineuses: utiliser des requêtes `dplyr` From 8b4be00e40e309934d094759f8f31f0d1e98709c Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Tue, 21 Nov 2023 19:28:32 +0100 Subject: [PATCH 13/92] Gros ajouts sur arrow --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 252 +++++++++++++++---- 1 file changed, 205 insertions(+), 47 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index bdbd9580..5f8fe010 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -1,77 +1,87 @@ # Manipuler des données avec `arrow` et `duckdb` {#arrow-duckdb} - ## Tâches concernées et recommandations L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-recommandation .icon} -* Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` qui font l'objet de la présente fiche. +- Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); + +- Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les *packages* `arrow` et `duckdb` qui font l'objet de la présente fiche. -- Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les _packages_ `arrow` et `duckdb` sont en cours de développement. +- Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les *packages* `arrow` et `duckdb` sont en cours de développement. ::: ::: {.callout-remarque .icon} -Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. +Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. -- Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. -- Il est complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`, il ne faut donc pas se décourager. -- Il ne faut pas hésiter à demander de l'aide à des collègues, ou à poser des questions sur les salons Tchap adaptés (le salon Langage `R` par exemple). +- Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. +- Il est complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`, il ne faut donc pas se décourager. +- Il ne faut pas hésiter à demander de l'aide à des collègues, ou à poser des questions sur les salons Tchap adaptés (le salon Langage `R` par exemple). ::: - -## Présentation des _packages_ `arrow` et `duckdb` +## Présentation des *packages* `arrow` et `duckdb` ### Qu'est-ce qu'`arrow`? -Apache `arrow` est un projet _open-source_ qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Un point important à retenir est donc que __`arrow` n'est pas un outil spécifique à `R`__, et il faut bien distinguer le projet `arrow` du _package_ `R` `arrow`. Ce _package_ propose simplement une interface qui permet d'utiliser le projet `arrow` avec `R`, et il existe d'autres interfaces pour se servir d'`arrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. - +Apache `arrow` est un projet *open-source* qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser le projet `arrow` avec `R`, et il existe d'autres interfaces pour se servir d'`arrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. ### Spécificités de `arrow` Le projet `arrow` présente cinq spécificités: -- Représentation des données en mémoire: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de _columnar format_). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, `arrow` va accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. +- Représentation des données en mémoire: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. -- Utilisation avec Parquet : `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. +- Utilisation avec Parquet : `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. -- Traitement de données volumineuses: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). +- Traitement de données volumineuses: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). -- Interopérabilité : `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. +- Interopérabilité : `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. -- _Lazy Evaluation_: `arrow` prend en charge la _lazy evaluation_ (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. +- *Lazy Evaluation*: `arrow` prend en charge la *lazy evaluation* (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. -### A quoi sert le _package_ `arrow`? +### A quoi sert le *package* `arrow`? -Du point de vue d'un statisticien utilisant `R`, le _package_ `arrow` permet de faire trois choses: - -- Importer des données (exemples: fichiers CSV, fichiers Parquet, stockage S3) et les stocker en mémoire vive en format `arrow`; -- Manipuler des données en format `arrow` selon la syntaxe `dplyr` ou en SQL (grâce à `duckdb`); -- Stocker des données en format Parquet. +Du point de vue d'un statisticien utilisant `R`, le *package* `arrow` permet de faire trois choses: +- Importer des données (exemples: fichiers CSV, fichiers Parquet, stockage S3) et les stocker en mémoire vive en format `arrow`; +- Manipuler des données en format `arrow` selon la syntaxe `dplyr`, ou avec le langage SQL (grâce à `duckdb`); +- Écrire des données en format Parquet. ### Quels sont les avantages d'`arrow`? -En pratique, le _package_ `arrow` présente trois avantages: +En pratique, le *package* `arrow` présente trois avantages: + +- **Performances élevées**: `arrow` est très efficace et très rapide pour la manipulation de données tabulaires (nettement plus performant que `dplyr` par exemple); +- **Usage réduit des ressources**: `arrow` est conçu pour ne charger en mémoire que le minimum de données. Cela permet de réduire considérablement les besoins en mémoire, même lorsque les données sont volumineuses; +- **Facilité d'apprentissage** grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. -- __Performances élevées__: `arrow` est très efficace et très rapide pour la manipulation de données tabulaires (nettement plus performant que `dplyr` par exemple); -- __Usage réduit des ressources__: `arrow` est conçu pour ne charger en mémoire que le minimum de données. Cela permet de réduire considérablement les besoins en mémoire, même lorsque les données sont volumineuses; -- __Facilité d'apprentissage__ grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. +## Que faut-il savoir pour utiliser `arrow`? +Le _package_ `arrow` présente quatre caractéristiques importantes: -## Comment utiliser `arrow`? +- une structure de données spécifique: le `Arrow Table`; +- une utilisation via la syntaxe `dplyr`; +- un moteur d'exécution spécifique: `acero`; +- un mode de fonctionnement particulier: l'évaluation différée. -Pour utiliser `arrow`, il faut commencer par charger le _package_. En pratique, `arrow` s'utilise presque toujours avec `dplyr`, il est donc préférable de prendre l'habitude de charger les deux _packages_ ensemble. +### Charger et paramétrer le `arrow` + +Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. ```{r} library(arrow) library(dplyr) + +# Autoriser arrow à utiliser plusieurs processeurs en parallèle +options(arrow.use_threads = TRUE) +# Définir le nombre de processeurs qu'arrow peut utiliser +arrow::set_cpu_count(parallel::detectCores() %/% 2) ``` ### Le `data.frame` version `arrow`: le `Arrow Table` -**Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. +**Le *package*`arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part et en `Arrow Table` d'autre part. @@ -85,7 +95,6 @@ bpe_ens_2018_arrow <- doremifasolData::bpe_ens_2018 |> as_arrow_table() Première différence: alors que les `data.frames` et les `tibbles` apparaissent dans la rubrique `Data` de l'environnement `RStudio` (cadre rouge dans la capture d'écran), les objets `Arrow Table` apparaissent dans la rubrique `Values` (cadre blanc). - ![](../pics/arrow/diff_environnement.png) Deuxième différence: alors que l'appel à un `data.frame` ou `tibble` en affiche les premières lignes, l'appel à un `Arrow Table` affiche uniquement des métadonnées (nombre de lignes et de colonnes, nom et type des colonnes). @@ -102,9 +111,8 @@ bpe_ens_2018_arrow Troisième différence: alors qu'il est possible d'afficher le contenu d'un `data.frame` ou d'un `tibble` en cliquant sur son nom dans la rubrique `Data` de l'environnement ou en utilisant la fonction `View()`, il n'est pas possible d'afficher directement le contenu d'un `Arrow Table`. Pour afficher le contenu d'un `Arrow Table`, il faut d'abord convertir le `Arrow Table` en `tibble` avec la fonction `collect()`. - ::: {.callout-conseil .icon} -Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` pose de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. __Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.__ Voici un exemple de code qui le fait: +Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` peut poser de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. **Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.** Voici un exemple de code qui le fait: ```{r, eval=FALSE} # Extraire les 1000 premières lignes du Arrow Table et les convertir en tibble @@ -114,26 +122,176 @@ View(extrait_bpe) ::: +### Manipuler des `Arrow Table` avec la syntaxe `dplyr` +__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme s'il cette table était un `data.frame` ou `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. -- la différence entre grammaire de traitement et moteur d'exécution; -- lazy evaluation avec arrow; -- La différence compute()/collect(); -- la différence entre charger les données avec `read_parquet` et `open_dataset`; -- La liste des fonctions connues par Acero; -- les fonctions définies par l'utilisateur (utilisation avancée) -- il est essentiel de rester en ArrowTable si on manipule des données volumineuses; -- l'interface arrow/duckdb -- l'utilisation de `duckdb` en plain SQL ou via `dbplyr`; +Voici un exemple dans lequel on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée. +
+ + + + + + + + +
Manipulation d'un `tibble`Manipulation d'un `Arrow Table`
+```{r eval=FALSE,message=FALSE} +bpe_ens_2018_tbl |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) +``` + +```{r eval=FALSE,message=FALSE} +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + collect() +``` +
-### Introduction +
-## Pour en savoir plus {#RessourcesArrow} -- la doc [`arrow`](xxx) ; -- la doc [`duckdb`](xxx) ; -- diverses ressources à citer. +### Le moteur d'exécution d'`arrow`: `acero` + +Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibble` et manipuler un `Arrow Table`, qui porte sur la __distinction entre syntaxe de manipulation des données et moteur d'exécution__. La syntaxe de manipulation des données sert à décrire décrire les manipulations de données qu'on veut faire (calculer des moyennes, faire des jointures...), indépendamment de la façon dont ces calculs sont effectivement réalisés. Inversement, le moteur d'exécution fait référence à la façon dont les opérations sur les données sont effectivement réalisées en mémoire, indépendamment de la façon dont elles ont été décrites par l'utilisateur. + +__La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table` tient au moteur d'exécution__: si on manipule un `tibble` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution de `dplyr` qui fait les calculs; si on manipule un `Arrow Table` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution d'`arrow` (nommé `acero`) qui fait les calculs. C'est justement parce que le moteur d'exécution d'`arrow` est beaucoup plus efficace que celui de `dplyr` qu'`arrow` est beaucoup plus rapide. + + + + + + +__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` sont automatiquement converties de façon invisible. La liste des fonctions du _tidyverse_ supportés par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". + + +### L'évaluation différée avec `arrow` (_lazy evaluation_) + +__Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Ces deux fonctions ont le même effet; la seule différence est que `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. + +__L'évaluation différée permet d'améliorer les performances en évitant le calcul de résultats intermédiaires inutiles, et en optimisant les requêtes__ pour utiliser le minimum de données et le minimum de ressources. L'exemple suivant illustre l'intérêt de l'évaluation différée dans un cas simple. + + +```{r, message=FALSE} +# Étape 1: compter les équipements par département +equipements_par_departement <- bpe_ens_2018_arrow |> + group_by(DEP) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) + +# Étape 2: filtrer sur le département +equipements_par_departement |> filter(DEP == "59") |> collect() +``` + + +Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement la requête (_query_) à appliquer à la table `bpe_ens_2018_arrow`. + +On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` se contente d'exécuter les instructions les unes après les autres: compter les équipements par département, puis conserver uniquement le département 59. Mais en réalité `arrow` fait beaucoup mieux que cela: __`arrow` analyse la requête avant de l'exécuter, et optimise le traitement pour minimiser le travail__. Dans le cas présent, `arrow` repère que la requête ne porte en fait que sur le département 59, et commence donc par filtrer les données sur le département avant de compter les équipements, de façon à ne conserver que le minimum de données nécessaires et à ne réaliser que le minimum de calculs. Ce type d'optimisation s'avère très utile quand les données à traiter sont très volumineuses. + +## Comment bien utiliser `arrow`? +### Savoir bien utiliser l'évaluation différée + +la différence entre charger les données avec `read_parquet` et `open_dataset`; + +### Utiliser des objets `Arrow Table` plutôt que des `tibble` + + + +il est essentiel de rester en ArrowTable avec compute() si on manipule des données volumineuses; + +### Comment utiliser une fonction non supportée par `acero` + + + +### Utiliser une fonction définie par l'utilisateur (utilisation avancée) + + + + + +
+ + + + + + + + + + + + + + + + + + +
Code exécuté dans `R`Signification
+```{r eval=FALSE,message=FALSE} +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) +``` +Définir une requête calculant le nombre total d'équipements par région (sans l'exécuter)
+```{r eval=FALSE,message=FALSE} +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + compute() +``` +Calculer le nombre total d'équipements par région et renvoyer les résultats dans un `Arrow Table`
+```{r eval=FALSE,message=FALSE} +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + collect() +``` +Calculer le nombre total d'équipements par région et renvoyer les résultats dans un `tibble`
+ +
+ +```{r} +# Définir une requête calculant le nombre total d'équipements par région (sans l'exécuter) +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) + +# Calculer le nombre total d'équipements par région et renvoyer un Arrow Table +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + compute() + +# Calculer le nombre total d'équipements par région et renvoyer un tibble +bpe_ens_2018_arrow |> + group_by(REG) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + collect() + +``` + +::: + +## Plan de la fiche + +- FAIT lazy evaluation avec arrow; +- FAIT La différence compute()/collect(); +- la différence entre charger les données avec `read_parquet` et `open_dataset`; +- FAIT La liste des fonctions connues par Acero; +- les fonctions définies par l'utilisateur (utilisation avancée) +- il est essentiel de rester en ArrowTable avec compute() si on manipule des données volumineuses; +- l'interface arrow/duckdb +- l'utilisation de `duckdb` en plain SQL ou via `dbplyr`; + +## Pour en savoir plus {#RessourcesArrow} +- la doc [`arrow`](xxx) ; +- la doc [`duckdb`](xxx) ; +- diverses ressources à citer. From 31d28a64e77e50f7d221b0218c0cd2284339c6ae Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Tue, 21 Nov 2023 19:36:13 +0100 Subject: [PATCH 14/92] Chunk options --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 5f8fe010..165791fc 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -69,7 +69,7 @@ Le _package_ `arrow` présente quatre caractéristiques importantes: Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. -```{r} +```{r, message=FALSE, warning=FALSE} library(arrow) library(dplyr) From b710f65d2f6a82c83b3d49217b439ad2f5af455e Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 22 Nov 2023 14:19:33 +0100 Subject: [PATCH 15/92] =?UTF-8?q?Compl=C3=A9ment=20sur=20compute/collect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 68 +++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 165791fc..04de94c6 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -139,14 +139,18 @@ Voici un exemple dans lequel on calcule le nombre d'équipements par région, à ```{r eval=FALSE,message=FALSE} bpe_ens_2018_tbl |> group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) ``` ```{r eval=FALSE,message=FALSE} bpe_ens_2018_arrow |> group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> collect() ``` @@ -196,13 +200,71 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ### Savoir bien utiliser l'évaluation différée + + + la différence entre charger les données avec `read_parquet` et `open_dataset`; ### Utiliser des objets `Arrow Table` plutôt que des `tibble` +__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`__. Cela implique d'utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires. L'exemple suivant explique pourquoi: + + +- Situation à éviter: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. + +- Usage recommandé: la première étape de traitement étant déclenchée par `compute()` (ligne 7), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. + +
+ + + + + + + + + + +
__Situation à éviter__: `collect()` dans les étapes intermédiaires __Usage recommandé__: `compute()` dans les étapes intermédiaires
+```{r eval=FALSE,message=FALSE, `code-line-numbers` = "1"} +# Etape 1 +res_intermediaire1 <- bpe_ens_2018_tbl |> + group_by(DEP) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> + collect() + +# Etape 2 +res_final <- res_intermediaire1 |> + filter(DEP == "59") |> + collect() + +# Sauvegarder les résultats +write_parquet(res_final, "resultats.parquet") +``` + +```{r eval=FALSE,message=FALSE, `code-line-numbers` = "1"} +# Etape 1 +res_intermediaire2 <- bpe_ens_2018_tbl |> + group_by(DEP) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> + compute() + +# Etape 2 +res_final <- res_intermediaire2 |> + filter(DEP == "59") |> + compute() + +# Sauvegarder les résultats +write_parquet(res_final, "resultats.parquet") +``` +
+
-il est essentiel de rester en ArrowTable avec compute() si on manipule des données volumineuses; ### Comment utiliser une fonction non supportée par `acero` From cb3b1b750d3ff9944f2a315dfc3655363b5ab015 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 22 Nov 2023 14:31:46 +0100 Subject: [PATCH 16/92] Coquille --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index 04de94c6..fe97a6b6 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -223,7 +223,7 @@ __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler un -```{r eval=FALSE,message=FALSE, `code-line-numbers` = "1"} +```{r eval=FALSE,message=FALSE} # Etape 1 res_intermediaire1 <- bpe_ens_2018_tbl |> group_by(DEP) |> @@ -242,7 +242,7 @@ write_parquet(res_final, "resultats.parquet") ``` -```{r eval=FALSE,message=FALSE, `code-line-numbers` = "1"} +```{r eval=FALSE,message=FALSE} # Etape 1 res_intermediaire2 <- bpe_ens_2018_tbl |> group_by(DEP) |> From 03a1fae5904f52e290a297d81c793b3b14d71a53 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 22 Nov 2023 17:06:02 +0100 Subject: [PATCH 17/92] Pleins d'ajouts sur arrow --- 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd | 253 +++++++++++-------- 1 file changed, 154 insertions(+), 99 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd index fe97a6b6..91166e08 100644 --- a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd +++ b/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd @@ -24,7 +24,7 @@ Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessit ### Qu'est-ce qu'`arrow`? -Apache `arrow` est un projet *open-source* qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser le projet `arrow` avec `R`, et il existe d'autres interfaces pour se servir d'`arrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. +Apache `arrow` est un projet *open-source* qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Ce projet prend la forme d'une librairie C++ nommée `libarrow`. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. ### Spécificités de `arrow` @@ -44,8 +44,8 @@ Le projet `arrow` présente cinq spécificités: Du point de vue d'un statisticien utilisant `R`, le *package* `arrow` permet de faire trois choses: -- Importer des données (exemples: fichiers CSV, fichiers Parquet, stockage S3) et les stocker en mémoire vive en format `arrow`; -- Manipuler des données en format `arrow` selon la syntaxe `dplyr`, ou avec le langage SQL (grâce à `duckdb`); +- Importer des données (exemples: fichiers CSV, fichiers Parquet, stockage S3) et les organiser en mémoire vive dans un objet `Arrow Table`; +- Manipuler des données organisées dans un `Arrow Table` avec la syntaxe `dplyr`, ou avec le langage SQL (grâce à `duckdb`); - Écrire des données en format Parquet. ### Quels sont les avantages d'`arrow`? @@ -83,7 +83,7 @@ arrow::set_cpu_count(parallel::detectCores() %/% 2) **Le *package*`arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. -Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part et en `Arrow Table` d'autre part. +Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part, et en `Arrow Table` d'autre part. ```{r} # Charger les données et les convertir en tibble @@ -124,33 +124,33 @@ View(extrait_bpe) ### Manipuler des `Arrow Table` avec la syntaxe `dplyr` -__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme s'il cette table était un `data.frame` ou `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. +__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme si cette table était un `data.frame` ou `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. -Voici un exemple dans lequel on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée. +Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée.
- - - - + + + + @@ -171,21 +171,21 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table -__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` sont automatiquement converties de façon invisible. La liste des fonctions du _tidyverse_ supportés par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". +__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` sont automatiquement converties de façon invisible. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". ### L'évaluation différée avec `arrow` (_lazy evaluation_) __Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Ces deux fonctions ont le même effet; la seule différence est que `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. - + __L'évaluation différée permet d'améliorer les performances en évitant le calcul de résultats intermédiaires inutiles, et en optimisant les requêtes__ pour utiliser le minimum de données et le minimum de ressources. L'exemple suivant illustre l'intérêt de l'évaluation différée dans un cas simple. ```{r, message=FALSE} # Étape 1: compter les équipements par département equipements_par_departement <- bpe_ens_2018_arrow |> - group_by(DEP) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) + group_by(DEP) |> + summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) # Étape 2: filtrer sur le département equipements_par_departement |> filter(DEP == "59") |> collect() @@ -198,21 +198,23 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? -### Savoir bien utiliser l'évaluation différée + + +### Utiliser des objets `Arrow Table` plutôt que des `tibble` +__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`__. Cela implique deux recommandations: -la différence entre charger les données avec `read_parquet` et `open_dataset`; +- Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`. Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. +- Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires. -### Utiliser des objets `Arrow Table` plutôt que des `tibble` +L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: -__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`__. Cela implique d'utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires. L'exemple suivant explique pourquoi: +- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. -- Situation à éviter: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. - -- Usage recommandé: la première étape de traitement étant déclenchée par `compute()` (ligne 7), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. +- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses.
@@ -265,95 +267,148 @@ write_parquet(res_final, "resultats.parquet")
+::: {.callout-conseil .icon} +Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. +::: -### Comment utiliser une fonction non supportée par `acero` +### Connaître les limites d'`arrow` +Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (décembre 2023): +- les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; +- les __empilements de tables__: il est possible d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions: -### Utiliser une fonction définie par l'utilisateur (utilisation avancée) + ```{r eval=FALSE,message=FALSE} + resultats <- table1 |> + union(table2) |> + union(table3) |> + union(table4) |> + compute() + ``` +- les __réorganisations de données__ (_wide-to-long_ et _long-to-wide_): il n'existe pas à ce jour dans `arrow` de fonctions pour réorganiser une table de données (comme `pivot_wider` et `pivot_longer` du _package_ `tidyr`). +### Surmonter le problème des fonctions non supportées par `acero` -
+__Lorsqu'on manipule des données avec `arrow`, il arrive fréquemment qu'on écrive un traitement que le moteur d'exécution `acero` n'arrive pas à exécuter.__ En ce cas, `R` renonce à manipuler les données sous forme de `Arrow Table` avec le moteur `acero`, convertit les données en `tibble` et poursuit le traitement avec le moteur d'exécution de `dplyr` (comme un traitement `dplyr` standard). `R` signale systématiquement le recours à cette solution de repli par un message d'erreur qui se termine par `pulling data into R`. -
Manipulation d'un `tibble`Manipulation d'un `Arrow Table`
Manipulation d'un `tibble`Manipulation d'un `Arrow Table`
```{r eval=FALSE,message=FALSE} bpe_ens_2018_tbl |> - group_by(REG) |> - summarise( - NB_EQUIP_TOT = sum(NB_EQUIP) - ) + group_by(REG) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) ``` ```{r eval=FALSE,message=FALSE} bpe_ens_2018_arrow |> - group_by(REG) |> - summarise( - NB_EQUIP_TOT = sum(NB_EQUIP) - ) |> + group_by(REG) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> collect() ```
- - - - - - - - - - +Le recours à cette solution de repli a pour conséquence de dégrader fortement les performances (car le moteur de `dplyr` est moins efficace qu'`acero`). __Il est donc préférable d'essayer de réécrire la partie du traitement qui pose problème avec des fonctions supportées par `acero`.__ Cela est particulièrement recommandé si les données manipulées sont volumineuses ou si le traitement concerné doit être exécuté fréquemment. - - - - - -
Code exécuté dans `R`Signification
-```{r eval=FALSE,message=FALSE} -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) -``` -Définir une requête calculant le nombre total d'équipements par région (sans l'exécuter)
-```{r eval=FALSE,message=FALSE} -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> - compute() -``` -Calculer le nombre total d'équipements par région et renvoyer les résultats dans un `Arrow Table`
-```{r eval=FALSE,message=FALSE} -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> - collect() -``` -Calculer le nombre total d'équipements par région et renvoyer les résultats dans un `tibble`
+#### Une solution simple existe-t-elle? -
+Dans la plupart des cas, il est possible de trouver une solution pour écrire un traitement que le moteur `acero` peut exécuter. Voici quelques pistes: -```{r} -# Définir une requête calculant le nombre total d'équipements par région (sans l'exécuter) -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) - -# Calculer le nombre total d'équipements par région et renvoyer un Arrow Table -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> - compute() +- Vérifier qu'on utilise la dernière version d'`arrow` et mettre à jour le _package_ si ce n'est pas le cas; +- Étudier en détail le message d'erreur renvoyé par `R` pour bien comprendre d'où vient le problème; +- Regarder la [liste des fonctions du _tidyverse_ supportées par `acero`](https://arrow.apache.org/docs/dev/r/reference/acero.html) pour voir s'il est possible d'utiliser une fonction supportée par `acero`; +- Faire des tests pour pour voir si une réécriture mineure du traitement peut régler le problème. -# Calculer le nombre total d'équipements par région et renvoyer un tibble -bpe_ens_2018_arrow |> - group_by(REG) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) |> - collect() +L'exemple qui suit montre comment on peut parfois trouver une solution très simple. Dans cet exemple, on veut calculer le nombre de boulangeries (`TYPEQU == "B203"`) et de poissonneries (`TYPEQU == "B206"`) dans chaque département, en stockant les résultats dans un `Arrow Table` (avec `compute()`). Malheureusement, `acero` ne parvient pas à réaliser ce traitement, et `R` est contraint de convertir les données en `tibble`. +```{r eval=FALSE,message=FALSE} +resultats <- bpe_ens_2018_arrow |> + group_by(DEP) |> + summarise( + nb_boulangeries = sum(NB_EQUIP * (TYPEQU == "B203")), + nb_poissonneries = sum(NB_EQUIP * (TYPEQU == "B206")) + ) |> + compute() ``` -::: +Le message d'erreur renvoyé par `R` est la suivante: `! NotImplemented: Function 'multiply_checked' has no kernel matching input types (double, bool); pulling data into `. En lisant attentivement le message d'erreur et en le rapprochant du traitement, on finit par comprendre que l'erreur vient de l'opération `sum(NB_EQUIP * (TYPEQU == "B203"))`: `arrow` ne parvient pas à faire la multiplication entre `NB_EQUIP` (un nombre réel) et `(TYPEQU == "B203")` (un booléen). La solution est très simple: il suffit de convertir `(TYPEQU == "B203")` en nombre entier avec la fonction `as.integer()` qui est supportée par `acero`. Le code suivant peut alors être entièrement exécuté par `acero`: -## Plan de la fiche +```{r eval=FALSE,message=FALSE} +resultats <- bpe_ens_2018_arrow |> + group_by(DEP) |> + summarise( + nb_boulangeries = sum(NB_EQUIP * as.integer(TYPEQU == "B203")), + nb_poissonneries = sum(NB_EQUIP * as.integer(TYPEQU == "B206")) + ) |> + compute() +``` -- FAIT lazy evaluation avec arrow; -- FAIT La différence compute()/collect(); -- la différence entre charger les données avec `read_parquet` et `open_dataset`; -- FAIT La liste des fonctions connues par Acero; -- les fonctions définies par l'utilisateur (utilisation avancée) -- il est essentiel de rester en ArrowTable avec compute() si on manipule des données volumineuses; -- l'interface arrow/duckdb -- l'utilisation de `duckdb` en plain SQL ou via `dbplyr`; +#### Définir soi-même des fonctions `arrow` (utilisation avancée) + +Si les pistes mentionnées précédemment ne fournissent pas de solution simple, il est possible d'aller plus loin et d'écrire ses propres fonctions `arrow`. Cette approche permet de faire beaucoup plus de choses mais elle nécessite de bien comprendre le fonctionnement d'`arrow` et les fonctions internes de la librairie `libarrow`. Il s'agit d'une utilisation avancée d'`arrow` qui dépasse le cadre de la documentation `utilitR`. Les lecteurs intéressés pourront consulter les deux ressources suivantes: + +- [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); +- la partie du [`Apache Arrow R Cookbook`](https://arrow.apache.org/cookbook/r/manipulating-data---tables.html#use-arrow-functions-in-dplyr-verbs-in-arrow) qui porte sur les `Arrow functions`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Pour en savoir plus {#RessourcesArrow} -- la doc [`arrow`](xxx) ; -- la doc [`duckdb`](xxx) ; -- diverses ressources à citer. +- documentation: + - la doc [`arrow`](xxx) (en anglais); + - [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); + + +- tutoriels: + - From e1147adfb30abb847a7a362f134b49566aa65255 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 22 Nov 2023 17:06:36 +0100 Subject: [PATCH 18/92] Changement de nom --- 03_Fiches_thematiques/{Fiche_arrow_duckdb.qmd => Fiche_arrow.qmd} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 03_Fiches_thematiques/{Fiche_arrow_duckdb.qmd => Fiche_arrow.qmd} (100%) diff --git a/03_Fiches_thematiques/Fiche_arrow_duckdb.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd similarity index 100% rename from 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd rename to 03_Fiches_thematiques/Fiche_arrow.qmd From 3ecc93196017ffe5ce605d053591685c2413cb31 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 22 Nov 2023 17:07:01 +0100 Subject: [PATCH 19/92] Adapter le quarto book --- _quarto.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_quarto.yml b/_quarto.yml index 4de80a3d..2123f30c 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -64,7 +64,7 @@ book: chapters: - 03_Fiches_thematiques/Fiche_tidyverse.qmd - 03_Fiches_thematiques/Fiche_datatable.qmd - - 03_Fiches_thematiques/Fiche_arrow_duckdb.qmd + - 03_Fiches_thematiques/Fiche_arrow.qmd - 03_Fiches_thematiques/Fiche_joindre_donnees.qmd - 03_Fiches_thematiques/Fiche_donnees_textuelles.qmd - 03_Fiches_thematiques/Fiche_survey.qmd From 0da399cf84bb6eef8d00a7a5a8912dcbac005c3f Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Wed, 22 Nov 2023 21:24:58 +0100 Subject: [PATCH 20/92] Petites modifs sur les recommandations --- 03_Fiches_thematiques/Fiche_arrow.qmd | 13 ++++++++----- 03_Fiches_thematiques/Fiche_datatable.qmd | 2 +- 03_Fiches_thematiques/Fiche_tidyverse.qmd | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 91166e08..65874d91 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -1,21 +1,24 @@ -# Manipuler des données avec `arrow` et `duckdb` {#arrow-duckdb} +# Manipuler des données avec `arrow` {#arrow} ## Tâches concernées et recommandations L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-recommandation .icon} -- Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); +- Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); -- Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit les *packages* `arrow` et `duckdb` qui font l'objet de la présente fiche. +- Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit le *package* `arrow` qui fait l'objet de la présente fiche, avec éventuellement `duckdb` en complément. + +- Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les *packages* `arrow` et `duckdb` sont en cours de développement. + +- Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`. Cela implique d'utiliser la fonction `compute()` plutôt que `collect()` dans les traitements intermédiaires. -- Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les *packages* `arrow` et `duckdb` sont en cours de développement. ::: ::: {.callout-remarque .icon} Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. -- Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire cette fiche. +- Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire la présente fiche. - Il est complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`, il ne faut donc pas se décourager. - Il ne faut pas hésiter à demander de l'aide à des collègues, ou à poser des questions sur les salons Tchap adaptés (le salon Langage `R` par exemple). ::: diff --git a/03_Fiches_thematiques/Fiche_datatable.qmd b/03_Fiches_thematiques/Fiche_datatable.qmd index 96a95a0f..448570d6 100644 --- a/03_Fiches_thematiques/Fiche_datatable.qmd +++ b/03_Fiches_thematiques/Fiche_datatable.qmd @@ -6,7 +6,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} * Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la présente fiche, soit les _packages_ `arrow` et `duckdb` présentés dans la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` qui fait l'objet de la présente fiche, soit les _packages_ `arrow` et `duckdb` présentés dans les fiches [Manipuler des données avec `arrow`](#arrow) et [Manipuler des données avec `duckdb`](#duckdb). ::: ::: {.callout-remarque .icon} diff --git a/03_Fiches_thematiques/Fiche_tidyverse.qmd b/03_Fiches_thematiques/Fiche_tidyverse.qmd index f274f620..a354e35b 100644 --- a/03_Fiches_thematiques/Fiche_tidyverse.qmd +++ b/03_Fiches_thematiques/Fiche_tidyverse.qmd @@ -8,7 +8,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} * Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui font l'objet de la présente fiche ; -* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` présenté dans la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` présentés dans la fiche [Manipuler des données avec `arrow` et `duckdb`](#arrow-duckdb). +* Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le _package_ `data.table` présenté dans la fiche [Manipuler des données avec `data.table`](#datatable), soit les _packages_ `arrow` et `duckdb` présentés dans les fiches [Manipuler des données avec `arrow`](#arrow) et [Manipuler des données avec `duckdb`](#duckdb). ::: ::: {.callout-remarque .icon} From bfaff299e1680742350a7126febb1c58e990f89d Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Wed, 22 Nov 2023 21:26:57 +0100 Subject: [PATCH 21/92] =?UTF-8?q?Pr=C3=A9cision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 65874d91..ca2702e0 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -11,7 +11,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f - Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les *packages* `arrow` et `duckdb` sont en cours de développement. -- Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`. Cela implique d'utiliser la fonction `compute()` plutôt que `collect()` dans les traitements intermédiaires. +- Si les données traitées sont très volumineuses (plus de 10 Go ou plus de 10 millions d'observations), il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`. Cela implique notamment d'utiliser la fonction `compute()` plutôt que `collect()` dans les traitements intermédiaires. ::: @@ -205,9 +205,9 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` -### Utiliser des objets `Arrow Table` plutôt que des `tibble` +### Utiliser des objets `Arrow Table` plutôt que des `tibbles` -__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibble`__. Cela implique deux recommandations: +__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`__. Cela implique deux recommandations: - Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`. Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. - Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires. From 0ddee93773ea1063ea03a3453ae359de1f5a4ae9 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 16:53:41 +0100 Subject: [PATCH 22/92] =?UTF-8?q?Rendre=20la=20formulation=20moins=20n?= =?UTF-8?q?=C3=A9gative?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index ca2702e0..cc5030c7 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -16,7 +16,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: ::: {.callout-remarque .icon} -Apprendre à bien utiliser `arrow` n'est ni simple ni rapide, car cela nécessite une bonne compréhension du fonctionnement de `R` et de `arrow`. +Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est quasiment identique à celle du `tidyverse`. Toutefois, une bonne compréhension du fonctionnement de `R` et de `arrow` est nécessaire pour bien utiliser `arrow` sur des données volumineuses. Voici quelques conseils pour bien démarrer: - Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire la présente fiche. - Il est complètement normal de rencontrer des erreurs difficiles à comprendre lorsqu'on commence à utiliser `arrow`, il ne faut donc pas se décourager. From f8eb55ae39eed6e5ecafef00fc9dd8071b909f32 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 17:06:26 +0100 Subject: [PATCH 23/92] =?UTF-8?q?Am=C3=A9liorations=20de=20d=C3=A9tail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index cc5030c7..2b61272d 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -33,15 +33,15 @@ Apache `arrow` est un projet *open-source* qui propose une représentation stand Le projet `arrow` présente cinq spécificités: -- Représentation des données en mémoire: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. +- __Représentation des données en mémoire__: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. -- Utilisation avec Parquet : `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. +- __Utilisation avec Parquet__: `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. -- Traitement de données volumineuses: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). +- __Traitement de données volumineuses__: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). -- Interopérabilité : `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. +- __Interopérabilité__: `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. -- *Lazy Evaluation*: `arrow` prend en charge la *lazy evaluation* (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. +- __*Lazy Evaluation*__: `arrow` prend en charge la *lazy evaluation* (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. ### A quoi sert le *package* `arrow`? @@ -70,7 +70,7 @@ Le _package_ `arrow` présente quatre caractéristiques importantes: ### Charger et paramétrer le `arrow` -Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. +Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. ```{r, message=FALSE, warning=FALSE} library(arrow) @@ -84,7 +84,7 @@ arrow::set_cpu_count(parallel::detectCores() %/% 2) ### Le `data.frame` version `arrow`: le `Arrow Table` -**Le *package*`arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. +**Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` ou un `tibble` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part, et en `Arrow Table` d'autre part. @@ -124,7 +124,6 @@ View(extrait_bpe) ``` ::: - ### Manipuler des `Arrow Table` avec la syntaxe `dplyr` __Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme si cette table était un `data.frame` ou `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. @@ -165,21 +164,21 @@ bpe_ens_2018_arrow |> ### Le moteur d'exécution d'`arrow`: `acero` -Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibble` et manipuler un `Arrow Table`, qui porte sur la __distinction entre syntaxe de manipulation des données et moteur d'exécution__. La syntaxe de manipulation des données sert à décrire décrire les manipulations de données qu'on veut faire (calculer des moyennes, faire des jointures...), indépendamment de la façon dont ces calculs sont effectivement réalisés. Inversement, le moteur d'exécution fait référence à la façon dont les opérations sur les données sont effectivement réalisées en mémoire, indépendamment de la façon dont elles ont été décrites par l'utilisateur. +Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibble` et manipuler un `Arrow Table`. Pour bien la comprendre, il faut d'abord comprendre la __distinction entre syntaxe de manipulation des données et moteur d'exécution__. La syntaxe de manipulation des données sert à décrire les manipulations de données qu'on veut faire (calculer des moyennes, faire des jointures...), indépendamment de la façon dont ces calculs sont effectivement réalisés. Inversement, le moteur d'exécution fait référence à la façon dont les opérations sur les données sont effectivement réalisées en mémoire, indépendamment de la façon dont elles ont été décrites par l'utilisateur. -__La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table` tient au moteur d'exécution__: si on manipule un `tibble` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution de `dplyr` qui fait les calculs; si on manipule un `Arrow Table` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution d'`arrow` (nommé `acero`) qui fait les calculs. C'est justement parce que le moteur d'exécution d'`arrow` est beaucoup plus efficace que celui de `dplyr` qu'`arrow` est beaucoup plus rapide. +__La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table` tient au moteur d'exécution__: si on manipule un `tibble` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution de `dplyr` qui fait les calculs; si on manipule un `Arrow Table` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution d'`arrow` (nommé `acero`) qui fait les calculs. C'est justement parce que le moteur d'exécution d'`arrow` est beaucoup plus efficace que celui de `dplyr` qu'`arrow` est beaucoup plus rapide. -__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` sont automatiquement converties de façon invisible. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". +__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". ### L'évaluation différée avec `arrow` (_lazy evaluation_) -__Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Ces deux fonctions ont le même effet; la seule différence est que `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. +__Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. __L'évaluation différée permet d'améliorer les performances en évitant le calcul de résultats intermédiaires inutiles, et en optimisant les requêtes__ pour utiliser le minimum de données et le minimum de ressources. L'exemple suivant illustre l'intérêt de l'évaluation différée dans un cas simple. @@ -194,8 +193,7 @@ equipements_par_departement <- bpe_ens_2018_arrow |> equipements_par_departement |> filter(DEP == "59") |> collect() ``` - -Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement la requête (_query_) à appliquer à la table `bpe_ens_2018_arrow`. +Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement une requête (_query_) à appliquer à la table `bpe_ens_2018_arrow`. On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` se contente d'exécuter les instructions les unes après les autres: compter les équipements par département, puis conserver uniquement le département 59. Mais en réalité `arrow` fait beaucoup mieux que cela: __`arrow` analyse la requête avant de l'exécuter, et optimise le traitement pour minimiser le travail__. Dans le cas présent, `arrow` repère que la requête ne porte en fait que sur le département 59, et commence donc par filtrer les données sur le département avant de compter les équipements, de façon à ne conserver que le minimum de données nécessaires et à ne réaliser que le minimum de calculs. Ce type d'optimisation s'avère très utile quand les données à traiter sont très volumineuses. From 1a319050fbfade14e4d26ab1eaa7dd986bbe73bc Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 17:17:34 +0100 Subject: [PATCH 24/92] Mise en forme --- 03_Fiches_thematiques/Fiche_arrow.qmd | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 2b61272d..5f01f111 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -176,7 +176,7 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table __Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". -### L'évaluation différée avec `arrow` (_lazy evaluation_) +### L'évaluation différée avec `arrow` (_lazy evaluation_) {#subsec-lazy} __Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. @@ -184,13 +184,17 @@ __L'évaluation différée permet d'améliorer les performances en évitant le c ```{r, message=FALSE} -# Étape 1: compter les équipements par département -equipements_par_departement <- bpe_ens_2018_arrow |> +# Étape 1: compter les équipements +eq_dep <- bpe_ens_2018_arrow |> group_by(DEP) |> - summarise(NB_EQUIP_TOT = sum(NB_EQUIP)) + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) # Étape 2: filtrer sur le département -equipements_par_departement |> filter(DEP == "59") |> collect() +resultats <- eq_dep |> + filter(DEP == "59") |> + collect() ``` Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement une requête (_query_) à appliquer à la table `bpe_ens_2018_arrow`. From 72b9896f7a688f90a607e89994136a6afcaa906a Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 18:35:32 +0100 Subject: [PATCH 25/92] =?UTF-8?q?Gros=20ajout=20sur=20les=20limites=20de?= =?UTF-8?q?=20l'=C3=A9valuation=20diff=C3=A9r=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 69 +++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 5f01f111..bf0cd703 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -203,18 +203,12 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? - - - - ### Utiliser des objets `Arrow Table` plutôt que des `tibbles` __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`__. Cela implique deux recommandations: -- Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`. Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. -- Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires. - -L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: +- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet` ou un fichier csv avec la fonction `arrow::read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. +- __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: - __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. @@ -276,6 +270,65 @@ write_parquet(res_final, "resultats.parquet") Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. ::: +### Savoir bien utiliser l'évaluation différée + +Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section + +#### Comprendre les limites de l'évaluation différée + +L'évaluation différée optimise les performances en minimisant la quantité de données chargées en RAM et la quantité de calculs effectivement réalisés. +Avec cette vision en tête, on pourrait penser que la meilleure façon d'utiliser `arrow` est d'écrire un traitement entier en mode _lazy_ (autrement dit: sans aucun `compute()` ni aucun `collect()` dans les étapes intermédiaires), et faire un unique `compute()` ou `collect()` tout à la fin du traitement, pour que toutes les opérations soient réalisées de façon optimisée en une seule étape. Un traitement idéal ressemblerait alors à ceci: + +```{r, eval=FALSE} +# Se connecter aux données +data1 <- open_dataset("data1.parquet") +data2 <- open_dataset("data2.parquet") + +# Une première étape de traitement +table_intermediaire1 <- data1 |> + select(...) |> + filter(...) |> + mutate(...) + +# Une deuxième étape de traitement +table_intermediaire2 <- data2 |> + select(...) |> + filter(...) |> + mutate(...) + +# Et encore beaucoup d'autres étapes de traitement +# avec beaucoup d'instructions... + +# La dernière étape du traitement +resultats <- table_intermediaire8 |> + left_join( + table_intermediaire9, + by = "identifiant" + ) |> + compute() + +write_parquet(resultats, "resultats.parquet") +``` + +La réalité n'est malheureusement pas si simple, car __l'évaluation différée a des limites__. En effet, au moment de produire le résultat final de l'exemple précédent, la fonction `compute()` donne l'instruction au moteur `acero` d'analyser puis d'exécuter _l'intégralité du traitement en une seule fois_. Or, le moteur `acero` est certes puissant, mais il a ses limites et ne peut pas exécuter en une seule fois des traitements vraiment trop complexes. Par exemple, `acero` rencontre des difficultés lorsqu'on enchaîne de multiples jointures de tables volumineuses. + +__Ces limites de l'évaluation différée peuvent provoquer des bugs violents__. Lorsque le moteur `acero` échoue à exécuter une requête trop complexe, les conséquences sont brutales: `R` n'imprime aucun message d'erreur, la session `R` plante et il faut simplement redémarrer `R` et tout recommencer. Il est donc nécessaire de bien structurer le traitement pour profiter des avantages de l'évaluation différée sans en toucher les limites. + +#### Accéder aux données avec `open_dataset` plutôt que `read_parquet` + +A écrire + +#### Décomposer le traitement en étapes cohérentes, puis le tester + +__La solution évidente pour ne pas toucher les limites de l'évaluation différée consiste à décomposer le traitement en étapes__, et à exécuter chaque étape séparément (en mettant un `compute()`). De cette façon, `acero` va réaliser séquentiellement plusieurs traitements un peu complexes, plutôt qu'échouer à réaliser un seul traitement très complexe en une seule fois. + +__La vraie difficulté consiste à savoir quelle est la bonne longueur de ces étapes intermédiaires__: s'il faut éviter de faire de très longues étapes (sinon l'évaluation différée plante), il faut également éviter d'exécuter une à une les étapes du traitement (sinon on perd les avantages de l'évaluation différée). Il n'y a pas de solution miracle, et seule la pratique permet de déterminer ce qui est raisonnable. Voici toutefois quelques conseils de bon sens: + +- __Un point de départ raisonnable peut consister à définir des étapes de traitement qui ne dépassent pas 30 ou 40 lignes de code__. Une étape de traitement de 200 lignes aura toutes les chances de poser des problèmes, d'autant qu'elle ne sera probablement pas très lisible. +- __Il est préférable que le séquencement des étapes soit cohérent avec l'objet du traitement.__ Par exemple, si l'ensemble du traitement consiste à retraiter séparément deux tables, puis à les joindre, on peut imaginer trois étapes qui s'achèvent chacune par un `compute()`: le retraitement de la première table, le retraitement de la seconde table, et la jointure. +- __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. +- __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont simplement des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. + ### Connaître les limites d'`arrow` Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (décembre 2023): From 20fe81e86d3f14316553da8054dab4a14c7c0629 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 18:40:57 +0100 Subject: [PATCH 26/92] =?UTF-8?q?Pr=C3=A9cision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index bf0cd703..4dd07110 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -363,7 +363,7 @@ Dans la plupart des cas, il est possible de trouver une solution pour écrire un - Regarder la [liste des fonctions du _tidyverse_ supportées par `acero`](https://arrow.apache.org/docs/dev/r/reference/acero.html) pour voir s'il est possible d'utiliser une fonction supportée par `acero`; - Faire des tests pour pour voir si une réécriture mineure du traitement peut régler le problème. -L'exemple qui suit montre comment on peut parfois trouver une solution très simple. Dans cet exemple, on veut calculer le nombre de boulangeries (`TYPEQU == "B203"`) et de poissonneries (`TYPEQU == "B206"`) dans chaque département, en stockant les résultats dans un `Arrow Table` (avec `compute()`). Malheureusement, `acero` ne parvient pas à réaliser ce traitement, et `R` est contraint de convertir les données en `tibble`. +L'exemple qui suit montre que la solution peut être très simple, même lorsque l'erreur semble complexe. Dans cet exemple, on veut calculer le nombre de boulangeries (`TYPEQU == "B203"`) et de poissonneries (`TYPEQU == "B206"`) dans chaque département, en stockant les résultats dans un `Arrow Table` (avec `compute()`). Malheureusement, `acero` ne parvient pas à réaliser ce traitement, et `R` est contraint de convertir les données en `tibble`. ```{r eval=FALSE,message=FALSE} resultats <- bpe_ens_2018_arrow |> @@ -375,7 +375,7 @@ resultats <- bpe_ens_2018_arrow |> compute() ``` -Le message d'erreur renvoyé par `R` est la suivante: `! NotImplemented: Function 'multiply_checked' has no kernel matching input types (double, bool); pulling data into `. En lisant attentivement le message d'erreur et en le rapprochant du traitement, on finit par comprendre que l'erreur vient de l'opération `sum(NB_EQUIP * (TYPEQU == "B203"))`: `arrow` ne parvient pas à faire la multiplication entre `NB_EQUIP` (un nombre réel) et `(TYPEQU == "B203")` (un booléen). La solution est très simple: il suffit de convertir `(TYPEQU == "B203")` en nombre entier avec la fonction `as.integer()` qui est supportée par `acero`. Le code suivant peut alors être entièrement exécuté par `acero`: +Le message d'erreur renvoyé par `R` est la suivante: `! NotImplemented: Function 'multiply_checked' has no kernel matching input types (double, bool); pulling data into R`. En lisant attentivement le message d'erreur et en le rapprochant du traitement, on finit par comprendre que l'erreur vient de l'opération `sum(NB_EQUIP * (TYPEQU == "B203"))`: `arrow` ne parvient pas à faire la multiplication entre `NB_EQUIP` (un nombre réel) et `(TYPEQU == "B203")` (un booléen). La solution est très simple: il suffit de convertir `(TYPEQU == "B203")` en nombre entier avec la fonction `as.integer()` qui est supportée par `acero`. Le code suivant peut alors être entièrement exécuté par `acero`: ```{r eval=FALSE,message=FALSE} resultats <- bpe_ens_2018_arrow |> From 32bf9186b02ac210c983dd3ffa33ba95b94faa87 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 8 Dec 2023 18:41:46 +0100 Subject: [PATCH 27/92] Adjectif --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 4dd07110..b5cd73ac 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -334,7 +334,7 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (décembre 2023): - les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; -- les __empilements de tables__: il est possible d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions: +- les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions: ```{r eval=FALSE,message=FALSE} resultats <- table1 |> From a64a91d511cbecd0ee2eae5261f6d2d3f165900a Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 10 Dec 2023 17:24:48 +0100 Subject: [PATCH 28/92] Coquille --- 03_Fiches_thematiques/Fiche_arrow.qmd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index b5cd73ac..d216b133 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -126,7 +126,7 @@ View(extrait_bpe) ### Manipuler des `Arrow Table` avec la syntaxe `dplyr` -__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme si cette table était un `data.frame` ou `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. +__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme si cette table était un `data.frame` ou un `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée. @@ -207,10 +207,9 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`__. Cela implique deux recommandations: -- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet` ou un fichier csv avec la fonction `arrow::read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. +- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. - __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: - - __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. - __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. From 08384af3d82c9fef8c7b6e376cb5bda47ce163d4 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 10 Dec 2023 17:25:05 +0100 Subject: [PATCH 29/92] Nettoyage --- 03_Fiches_thematiques/Fiche_arrow.qmd | 6 ------ 1 file changed, 6 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d216b133..6f2b1beb 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -313,10 +313,6 @@ La réalité n'est malheureusement pas si simple, car __l'évaluation différée __Ces limites de l'évaluation différée peuvent provoquer des bugs violents__. Lorsque le moteur `acero` échoue à exécuter une requête trop complexe, les conséquences sont brutales: `R` n'imprime aucun message d'erreur, la session `R` plante et il faut simplement redémarrer `R` et tout recommencer. Il est donc nécessaire de bien structurer le traitement pour profiter des avantages de l'évaluation différée sans en toucher les limites. -#### Accéder aux données avec `open_dataset` plutôt que `read_parquet` - -A écrire - #### Décomposer le traitement en étapes cohérentes, puis le tester __La solution évidente pour ne pas toucher les limites de l'évaluation différée consiste à décomposer le traitement en étapes__, et à exécuter chaque étape séparément (en mettant un `compute()`). De cette façon, `acero` va réaliser séquentiellement plusieurs traitements un peu complexes, plutôt qu'échouer à réaliser un seul traitement très complexe en une seule fois. @@ -345,8 +341,6 @@ Le projet `arrow` est relativement récent et en développement actif. Il n'est - les __réorganisations de données__ (_wide-to-long_ et _long-to-wide_): il n'existe pas à ce jour dans `arrow` de fonctions pour réorganiser une table de données (comme `pivot_wider` et `pivot_longer` du _package_ `tidyr`). - - ### Surmonter le problème des fonctions non supportées par `acero` __Lorsqu'on manipule des données avec `arrow`, il arrive fréquemment qu'on écrive un traitement que le moteur d'exécution `acero` n'arrive pas à exécuter.__ En ce cas, `R` renonce à manipuler les données sous forme de `Arrow Table` avec le moteur `acero`, convertit les données en `tibble` et poursuit le traitement avec le moteur d'exécution de `dplyr` (comme un traitement `dplyr` standard). `R` signale systématiquement le recours à cette solution de repli par un message d'erreur qui se termine par `pulling data into R`. From 6fe4b4bd18e0d5e9071eefa0a3b01528379c2033 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 10 Dec 2023 17:36:49 +0100 Subject: [PATCH 30/92] =?UTF-8?q?En=20l'=C3=A9tat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 76 ++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 6f2b1beb..1ac07003 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -269,11 +269,83 @@ write_parquet(res_final, "resultats.parquet") Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. ::: +### Accéder aux fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` + +__Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: + +- __Consommation mémoire inférieure__: la fonction `open_dataset()` crée une connexion au fichier Parquet, mais elle n'importe pas les données contenues dans le fichier tant que l'utilisateur ne le demande pas avec `compute()` ou `collect()`, et elle est optimisée pour importer uniquement les données nécessaires au traitement. Inversement, la fonction `read_parquet()` importe immédiatement dans `R` toutes les données du fichier Parquet, y compris des données qui ne servent pas à la suite du traitement. +- __Usage plus général__: la fonction `open_dataset()` peut se connecter à un fichier Parquet unique, mais aussi à des fichiers Parquet partitionnés, tandis que `read_parquet()` ne peut pas lire ces derniers. + + ### Savoir bien utiliser l'évaluation différée -Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section +Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. + +```{r, message=FALSE} +# Sauvegarder la BPE 2018 sous la forme d'un dataset Arrow partitionné +write_dataset( + bpe_ens_2018_arrow, + "bpe2018/", + partitioning = "REG", + hive_style = TRUE +) +``` + +#### Comment fonctionne l'évaluation différée? + +Ce paragraphe s'adresse aux lecteurs qui souhaitent comprendre plus en détail le fonctionnement de l'évaluation différée. Les lecteurs pressés peuvent passer directement au paragraphe suivant, sur les limites de l'évaluation différée. + +Le traitement suivant est un exemple simple d'utilisation de l'évaluation différée. Ce traitement comprend trois étapes: se connecter aux données avec `open_dataset()`, puis calculer le nombre d'équipements par département, et enfin sélectionner le département 59. + +```{r, message=FALSE} +# Étape 1: se connecter au fichier Paruet Partitionné +ds_bpe2018 <- open_dataset( + "bpe2018/", + partitioning = schema("REG" = utf8()), + hive_style = TRUE +) + +# Étape 2: compter les équipements +eq_dep <- ds_bpe2018 |> + group_by(DEP) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) + +# Étape 3: filtrer sur le département +resultats <- eq_dep |> + filter(DEP == "59") +``` + + +```{r, message=FALSE} +# Imprimer la première requête +show_exec_plan(ds_bpe2018) +``` + + + +- Le code ci-dessous n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. +- Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes de classe `arrow_dplyr_query`, qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `R` d'exécuter ces requêtes. + + +```{r, message=FALSE} +# Imprimer la deuxième requête, qui contient la première +show_exec_plan(eq_dep) +``` + +```{r, message=FALSE} +# Imprimer la troisième requête, qui contient les deux premières +show_exec_plan(resultats) +``` + +Expliquer la notion de `arrow_dplyr_query` + + +Plus un traitement est long, plus la requête est longue et complexe. + -#### Comprendre les limites de l'évaluation différée +#### Quelles sont les limites de l'évaluation différée? L'évaluation différée optimise les performances en minimisant la quantité de données chargées en RAM et la quantité de calculs effectivement réalisés. Avec cette vision en tête, on pourrait penser que la meilleure façon d'utiliser `arrow` est d'écrire un traitement entier en mode _lazy_ (autrement dit: sans aucun `compute()` ni aucun `collect()` dans les étapes intermédiaires), et faire un unique `compute()` ou `collect()` tout à la fin du traitement, pour que toutes les opérations soient réalisées de façon optimisée en une seule étape. Un traitement idéal ressemblerait alors à ceci: From 1a6f6717cb34d4dfa22d06a68ccf2479385d329e Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 10:24:25 +0100 Subject: [PATCH 31/92] =?UTF-8?q?Compl=C3=A9ment=20sur=20les=20recommandat?= =?UTF-8?q?ions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 1ac07003..b5183a92 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -7,11 +7,11 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: {.callout-recommandation .icon} - Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); -- Pour des tables de données de grande taille (plus de 1 Go ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit le *package* `arrow` qui fait l'objet de la présente fiche, avec éventuellement `duckdb` en complément. +- Pour des tables de données de grande taille (plus de 1 Go en CSV, plus de 200 Mo en Parquet, ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit le *package* `arrow` qui fait l'objet de la présente fiche, avec éventuellement `duckdb` en complément. - Il est essentiel de travailler avec la dernière version d'`arrow`, de `duckdb` et de `R` car les *packages* `arrow` et `duckdb` sont en cours de développement. -- Si les données traitées sont très volumineuses (plus de 10 Go ou plus de 10 millions d'observations), il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`. Cela implique notamment d'utiliser la fonction `compute()` plutôt que `collect()` dans les traitements intermédiaires. +- Si les données traitées sont très volumineuses (plus de 5 Go en CSV, plus de 1 Go en Parquet ou plus de 5 millions d'observations), il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`. Cela implique notamment d'utiliser la fonction `compute()` plutôt que `collect()` dans les traitements intermédiaires. ::: @@ -178,7 +178,7 @@ __Cette différence de moteurs d'exécution a une conséquence technique importa ### L'évaluation différée avec `arrow` (_lazy evaluation_) {#subsec-lazy} -__Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de et ne fait aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. +__Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de mémoriser les instructions, sans faire aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. __L'évaluation différée permet d'améliorer les performances en évitant le calcul de résultats intermédiaires inutiles, et en optimisant les requêtes__ pour utiliser le minimum de données et le minimum de ressources. L'exemple suivant illustre l'intérêt de l'évaluation différée dans un cas simple. From 1cb91a73157feccf50cba16e6c653d7cc9b4a99b Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:08:55 +0100 Subject: [PATCH 32/92] =?UTF-8?q?Am=C3=A9liorer=20les=20formulations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index b5183a92..116258b6 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -27,13 +27,18 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est ### Qu'est-ce qu'`arrow`? -Apache `arrow` est un projet *open-source* qui propose une représentation standardisée des données tabulaires en mémoire vive, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. Ce projet prend la forme d'une librairie C++ nommée `libarrow`. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. +Apache `arrow` est un projet *open-source* qui propose deux choses: + +- une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. +- une implémentation de ce standard en C++, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. + +Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. ### Spécificités de `arrow` Le projet `arrow` présente cinq spécificités: -- __Représentation des données en mémoire__: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. +- __Représentation des données en mémoire__: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient l'intégralité de cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. - __Utilisation avec Parquet__: `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. @@ -126,7 +131,7 @@ View(extrait_bpe) ### Manipuler des `Arrow Table` avec la syntaxe `dplyr` -__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), comme si cette table était un `data.frame` ou un `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. +__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), *comme si* cette table était un `data.frame` ou un `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. Il y a néanmoins des subtilités à connaître, détaillées dans la suite de cette fiche. Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée. @@ -168,12 +173,10 @@ Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibbl __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table` tient au moteur d'exécution__: si on manipule un `tibble` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution de `dplyr` qui fait les calculs; si on manipule un `Arrow Table` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution d'`arrow` (nommé `acero`) qui fait les calculs. C'est justement parce que le moteur d'exécution d'`arrow` est beaucoup plus efficace que celui de `dplyr` qu'`arrow` est beaucoup plus rapide. - - -__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (implémenté en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". +__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". ### L'évaluation différée avec `arrow` (_lazy evaluation_) {#subsec-lazy} @@ -197,7 +200,7 @@ resultats <- eq_dep |> collect() ``` -Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement une requête (_query_) à appliquer à la table `bpe_ens_2018_arrow`. +Dans cet exemple, on procède à un traitement en deux temps: on compte les équipements par département, puis on filtre sur le département. Il est important de souligner que la première étape ne réalise aucun calcul par elle-même, car elle ne comprend ni `collect()` ni `compute()`. L'objet `equipements_par_departement` n'est pas une table et ne contient pas de données, il contient simplement une requête (_query_) décrivant les opérations à mener sur la table `bpe_ens_2018_arrow`. On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` se contente d'exécuter les instructions les unes après les autres: compter les équipements par département, puis conserver uniquement le département 59. Mais en réalité `arrow` fait beaucoup mieux que cela: __`arrow` analyse la requête avant de l'exécuter, et optimise le traitement pour minimiser le travail__. Dans le cas présent, `arrow` repère que la requête ne porte en fait que sur le département 59, et commence donc par filtrer les données sur le département avant de compter les équipements, de façon à ne conserver que le minimum de données nécessaires et à ne réaliser que le minimum de calculs. Ce type d'optimisation s'avère très utile quand les données à traiter sont très volumineuses. @@ -207,7 +210,7 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`__. Cela implique deux recommandations: -- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées dans un `Arrow Table`. +- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. - __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: - __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. From 18895dcbfd5818570525fc66b1f6f32dc83056ed Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:16:45 +0100 Subject: [PATCH 33/92] up --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 116258b6..4468ff44 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -401,7 +401,7 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é ### Connaître les limites d'`arrow` -Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (décembre 2023): +Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): - les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; - les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions: From e5b93e975b5500a56057d25597b991f5ec21221e Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:22:36 +0100 Subject: [PATCH 34/92] =?UTF-8?q?Mise=20=C3=A0=20jour=20GHA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/bookdown-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bookdown-test.yaml b/.github/workflows/bookdown-test.yaml index fd8f7963..67c37673 100644 --- a/.github/workflows/bookdown-test.yaml +++ b/.github/workflows/bookdown-test.yaml @@ -30,7 +30,7 @@ jobs: - name: Render Book run: | quarto render - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: _public path: _public/ From 99082f823b87775d382260dee5338ca32b16a729 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:42:58 +0100 Subject: [PATCH 35/92] =?UTF-8?q?Compl=C3=A9ment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 35 ++++++++++----------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 4468ff44..03ea3653 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -282,7 +282,7 @@ __Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` p ### Savoir bien utiliser l'évaluation différée -Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. +Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. ```{r, message=FALSE} # Sauvegarder la BPE 2018 sous la forme d'un dataset Arrow partitionné @@ -320,18 +320,17 @@ resultats <- eq_dep |> filter(DEP == "59") ``` +Voici quelques commentaires pour comprendre ce traitement: + +- Le code ci-dessus n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. +- Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes (de classe `arrow_dplyr_query`), qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `arrow` d'exécuter ces requêtes avec le moteur `acero`. +- Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. La deuxième requête est un peu plus longue, et si on regarde en détail, on constate qu'elle contient la première requête. Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. ```{r, message=FALSE} # Imprimer la première requête show_exec_plan(ds_bpe2018) ``` - - -- Le code ci-dessous n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. -- Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes de classe `arrow_dplyr_query`, qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `R` d'exécuter ces requêtes. - - ```{r, message=FALSE} # Imprimer la deuxième requête, qui contient la première show_exec_plan(eq_dep) @@ -342,11 +341,6 @@ show_exec_plan(eq_dep) show_exec_plan(resultats) ``` -Expliquer la notion de `arrow_dplyr_query` - - -Plus un traitement est long, plus la requête est longue et complexe. - #### Quelles sont les limites de l'évaluation différée? @@ -384,7 +378,7 @@ resultats <- table_intermediaire8 |> write_parquet(resultats, "resultats.parquet") ``` -La réalité n'est malheureusement pas si simple, car __l'évaluation différée a des limites__. En effet, au moment de produire le résultat final de l'exemple précédent, la fonction `compute()` donne l'instruction au moteur `acero` d'analyser puis d'exécuter _l'intégralité du traitement en une seule fois_. Or, le moteur `acero` est certes puissant, mais il a ses limites et ne peut pas exécuter en une seule fois des traitements vraiment trop complexes. Par exemple, `acero` rencontre des difficultés lorsqu'on enchaîne de multiples jointures de tables volumineuses. +La réalité n'est malheureusement pas si simple, car __l'évaluation différée a des limites__. En effet, au moment de produire le résultat final de l'exemple précédent, la fonction `compute()` donne l'instruction au moteur `acero` d'analyser puis d'exécuter _l'intégralité du traitement en une seule fois_ (le paragraphe précédent donne un exemple détaillé). Or, le moteur `acero` est certes puissant, mais il a ses limites et ne peut pas exécuter en une seule fois des traitements vraiment trop complexes. Par exemple, `acero` rencontre des difficultés lorsqu'on enchaîne de multiples jointures de tables volumineuses. __Ces limites de l'évaluation différée peuvent provoquer des bugs violents__. Lorsque le moteur `acero` échoue à exécuter une requête trop complexe, les conséquences sont brutales: `R` n'imprime aucun message d'erreur, la session `R` plante et il faut simplement redémarrer `R` et tout recommencer. Il est donc nécessaire de bien structurer le traitement pour profiter des avantages de l'évaluation différée sans en toucher les limites. @@ -397,16 +391,17 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é - __Un point de départ raisonnable peut consister à définir des étapes de traitement qui ne dépassent pas 30 ou 40 lignes de code__. Une étape de traitement de 200 lignes aura toutes les chances de poser des problèmes, d'autant qu'elle ne sera probablement pas très lisible. - __Il est préférable que le séquencement des étapes soit cohérent avec l'objet du traitement.__ Par exemple, si l'ensemble du traitement consiste à retraiter séparément deux tables, puis à les joindre, on peut imaginer trois étapes qui s'achèvent chacune par un `compute()`: le retraitement de la première table, le retraitement de la seconde table, et la jointure. - __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. -- __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont simplement des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. +- __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème, car ces opérations sont simples. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. ### Connaître les limites d'`arrow` Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): - les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; -- les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions: +- les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions. Par ailleurs, les deux `Arrow Table` doivent être parfaitement compatibles pour être empilés (il faut le même nombre de colonnes avec le même nom et le même type, ce qui n'est pas toujours le cas en pratique). ```{r eval=FALSE,message=FALSE} + # Comment empiler de multiples Arrow Tables resultats <- table1 |> union(table2) |> union(table3) |> @@ -424,7 +419,7 @@ Le recours à cette solution de repli a pour conséquence de dégrader fortement #### Une solution simple existe-t-elle? -Dans la plupart des cas, il est possible de trouver une solution pour écrire un traitement que le moteur `acero` peut exécuter. Voici quelques pistes: +Dans la plupart des cas, il est possible de trouver une solution simple pour écrire un traitement que le moteur `acero` peut exécuter. Voici quelques pistes: - Vérifier qu'on utilise la dernière version d'`arrow` et mettre à jour le _package_ si ce n'est pas le cas; - Étudier en détail le message d'erreur renvoyé par `R` pour bien comprendre d'où vient le problème; @@ -531,10 +526,6 @@ Si les pistes mentionnées précédemment ne fournissent pas de solution simple, ## Pour en savoir plus {#RessourcesArrow} -- documentation: - - la doc [`arrow`](xxx) (en anglais); - - [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); - +- la documentation officielle du _package_ [`arrow`](https://arrow.apache.org/docs/dev/r/index.html) (en anglais); +- [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); -- tutoriels: - - From 25b77f223bca3725cc20b12ff42e7bdf06df416d Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:46:48 +0100 Subject: [PATCH 36/92] Recommandation --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 03ea3653..bf69297b 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -4,7 +4,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). -::: {.callout-recommandation .icon} +::: {.callout-important} - Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); - Pour des tables de données de grande taille (plus de 1 Go en CSV, plus de 200 Mo en Parquet, ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit le *package* `arrow` qui fait l'objet de la présente fiche, avec éventuellement `duckdb` en complément. From f2b5dd317c319e7329fe705f1bad9c8a3e1c67e3 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:51:21 +0100 Subject: [PATCH 37/92] gras --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index bf69297b..10539714 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -29,8 +29,8 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est Apache `arrow` est un projet *open-source* qui propose deux choses: -- une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. -- une implémentation de ce standard en C++, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. +- **une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_**, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. +- **une implémentation de ce standard en C++**, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. From 9c5c325c874091d48a5dae668873e22c00c91215 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 11:59:50 +0100 Subject: [PATCH 38/92] Mise en forme --- 03_Fiches_thematiques/Fiche_arrow.qmd | 38 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 10539714..2deb8dd2 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -324,22 +324,28 @@ Voici quelques commentaires pour comprendre ce traitement: - Le code ci-dessus n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. - Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes (de classe `arrow_dplyr_query`), qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `arrow` d'exécuter ces requêtes avec le moteur `acero`. -- Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. La deuxième requête est un peu plus longue, et si on regarde en détail, on constate qu'elle contient la première requête. Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. - -```{r, message=FALSE} -# Imprimer la première requête -show_exec_plan(ds_bpe2018) -``` - -```{r, message=FALSE} -# Imprimer la deuxième requête, qui contient la première -show_exec_plan(eq_dep) -``` - -```{r, message=FALSE} -# Imprimer la troisième requête, qui contient les deux premières -show_exec_plan(resultats) -``` +- Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. + + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. + + ```{r, message=FALSE} + # Imprimer la première requête + show_exec_plan(ds_bpe2018) + ``` + + + + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses: elle contient la première requête, et elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). + + ```{r, message=FALSE} + # Imprimer la deuxième requête, qui contient la première + show_exec_plan(eq_dep) + ``` + + + Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. + + ```{r, message=FALSE} + # Imprimer la troisième requête, qui contient les deux premières + show_exec_plan(resultats) + ``` #### Quelles sont les limites de l'évaluation différée? From d9ae81b1777e4c824263ba5c0fd6ceff472fc75f Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 12:04:45 +0100 Subject: [PATCH 39/92] Boite --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 2deb8dd2..23fa8713 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -15,7 +15,8 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.f ::: -::: {.callout-remarque .icon} +::: {.callout-note} + Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est quasiment identique à celle du `tidyverse`. Toutefois, une bonne compréhension du fonctionnement de `R` et de `arrow` est nécessaire pour bien utiliser `arrow` sur des données volumineuses. Voici quelques conseils pour bien démarrer: - Il est indispensable de lire les fiches [Importer des fichiers Parquet](#importparquet) et [Manipuler des données avec le `tidyverse`](#tidyverse) avant de lire la présente fiche. From 4d46433a8fa31a6347db99c091bfa637f72d7bdb Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 13:21:09 +0100 Subject: [PATCH 40/92] Indentation --- 03_Fiches_thematiques/Fiche_arrow.qmd | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 23fa8713..c7f2197c 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -328,25 +328,24 @@ Voici quelques commentaires pour comprendre ce traitement: - Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. - ```{r, message=FALSE} - # Imprimer la première requête - show_exec_plan(ds_bpe2018) - ``` - +```{r, message=FALSE} +# Imprimer la première requête +show_exec_plan(ds_bpe2018) +``` + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses: elle contient la première requête, et elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). - ```{r, message=FALSE} - # Imprimer la deuxième requête, qui contient la première - show_exec_plan(eq_dep) - ``` +```{r, message=FALSE} +# Imprimer la deuxième requête, qui contient la première +show_exec_plan(eq_dep) +``` + Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. - ```{r, message=FALSE} - # Imprimer la troisième requête, qui contient les deux premières - show_exec_plan(resultats) - ``` +```{r, message=FALSE} +# Imprimer la troisième requête, qui contient les deux premières +show_exec_plan(resultats) +``` #### Quelles sont les limites de l'évaluation différée? From 937cafb4883a7b1dcf3030d2553fff98c10a44f2 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 13:28:42 +0100 Subject: [PATCH 41/92] Cross ref --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index c7f2197c..a950221a 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -180,7 +180,7 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table __Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". -### L'évaluation différée avec `arrow` (_lazy evaluation_) {#subsec-lazy} +### L'évaluation différée avec `arrow` (_lazy evaluation_) {#sec-lazy} __Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de mémoriser les instructions, sans faire aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. @@ -283,7 +283,7 @@ __Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` p ### Savoir bien utiliser l'évaluation différée -Le paragraphe @subsec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. +Le paragraphe @sec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. ```{r, message=FALSE} # Sauvegarder la BPE 2018 sous la forme d'un dataset Arrow partitionné From 30f86e1ba373077a7f0345ed5f794721e0261527 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 13:44:43 +0100 Subject: [PATCH 42/92] Bricoles --- 03_Fiches_thematiques/Fiche_arrow.qmd | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index a950221a..1f1538b0 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -325,27 +325,28 @@ Voici quelques commentaires pour comprendre ce traitement: - Le code ci-dessus n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. - Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes (de classe `arrow_dplyr_query`), qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `arrow` d'exécuter ces requêtes avec le moteur `acero`. -- Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. - + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. - -```{r, message=FALSE} -# Imprimer la première requête -show_exec_plan(ds_bpe2018) -``` - - + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses: elle contient la première requête, et elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). - -```{r, message=FALSE} -# Imprimer la deuxième requête, qui contient la première -show_exec_plan(eq_dep) -``` - +- Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. + + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. + + ```{r, message=FALSE} + # Imprimer la première requête + show_exec_plan(ds_bpe2018) + ``` + + + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate trois choses: elle contient la première requête, elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`), et le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). + + ```{r, message=FALSE} + # Imprimer la deuxième requête, qui contient la première + show_exec_plan(eq_dep) + ``` + + Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. -```{r, message=FALSE} -# Imprimer la troisième requête, qui contient les deux premières -show_exec_plan(resultats) -``` + ```{r, message=FALSE} + # Imprimer la troisième requête, qui contient les deux premières + show_exec_plan(resultats) + ``` + #### Quelles sont les limites de l'évaluation différée? From deed123a5bee872e3d5f7567df4b2614072ec4a3 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 13:48:38 +0100 Subject: [PATCH 43/92] Formulation --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 1f1538b0..977f8313 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -333,7 +333,7 @@ Voici quelques commentaires pour comprendre ce traitement: show_exec_plan(ds_bpe2018) ``` - + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate trois choses: elle contient la première requête, elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`), et le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). + + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses. Premièrement, elle contient la première requête, mais elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). Deuxièmement, on retrouve tous les éléments du traitement (notamment le `group_by` et la somme), mais le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). ```{r, message=FALSE} # Imprimer la deuxième requête, qui contient la première From 7f139472106614a81569bf19f02adb0f1227a07c Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 14:03:27 +0100 Subject: [PATCH 44/92] Mise en forme --- 03_Fiches_thematiques/Fiche_arrow.qmd | 38 +++++++++++++-------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 977f8313..4bee4dbd 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -326,29 +326,27 @@ Voici quelques commentaires pour comprendre ce traitement: - Le code ci-dessus n'effectue aucun calcul, car il ne comprend ni `collect()` ni `compute()`. Il faut exécuter `resultats |> collect()` ou `resultats |> compute()` pour que les calculs soient effectivement réalisés. - Les objets `ds_bpe2018`, `eq_dep` et `resultats` ne sont pas des tables `R` standards contenant des données: ce sont des requêtes (de classe `arrow_dplyr_query`), qui décrivent des opérations à mener sur des données. C'est justement en utilisant `collect()` ou `compute()` qu'on demande à `arrow` d'exécuter ces requêtes avec le moteur `acero`. - Il est possible d'afficher le contenu des requêtes avec la fonction `show_exec_plan()`. - + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. + + La première requête est très courte: elle ne contient que la description des données contenues dans le fichier Parquet partitionné. - ```{r, message=FALSE} - # Imprimer la première requête - show_exec_plan(ds_bpe2018) - ``` + ```{r, message=FALSE} + # Imprimer la première requête + show_exec_plan(ds_bpe2018) + ``` - + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses. Premièrement, elle contient la première requête, mais elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). Deuxièmement, on retrouve tous les éléments du traitement (notamment le `group_by` et la somme), mais le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). + + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses. Premièrement, elle contient la première requête, mais elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). Deuxièmement, on retrouve tous les éléments du traitement (notamment le `group_by` et la somme), mais le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). - ```{r, message=FALSE} - # Imprimer la deuxième requête, qui contient la première - show_exec_plan(eq_dep) - ``` + ```{r, message=FALSE} + # Imprimer la deuxième requête, qui contient la première + show_exec_plan(eq_dep) + ``` - + Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, la troisième requête contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. + + Enfin, la troisième requête est encore plus longue, et contient les deux premières. Autrement dit, elle contient l'intégralité du traitement, donc on réalise l'intégralité du traitement lorsqu'on exécute cette requête avec `resultats |> collect()`. - ```{r, message=FALSE} - # Imprimer la troisième requête, qui contient les deux premières - show_exec_plan(resultats) - ``` + ```{r, message=FALSE} + # Imprimer la troisième requête, qui contient les deux premières + show_exec_plan(resultats) + ``` - - #### Quelles sont les limites de l'évaluation différée? L'évaluation différée optimise les performances en minimisant la quantité de données chargées en RAM et la quantité de calculs effectivement réalisés. @@ -391,7 +389,7 @@ __Ces limites de l'évaluation différée peuvent provoquer des bugs violents__. #### Décomposer le traitement en étapes cohérentes, puis le tester -__La solution évidente pour ne pas toucher les limites de l'évaluation différée consiste à décomposer le traitement en étapes__, et à exécuter chaque étape séparément (en mettant un `compute()`). De cette façon, `acero` va réaliser séquentiellement plusieurs traitements un peu complexes, plutôt qu'échouer à réaliser un seul traitement très complexe en une seule fois. +__La solution évidente pour ne pas toucher les limites de l'évaluation différée consiste à décomposer le traitement en étapes__, et à exécuter chaque étape séparément, en mettant un `compute()`. De cette façon, `acero` va réaliser séquentiellement plusieurs traitements un peu complexes, plutôt qu'échouer à réaliser un seul traitement très complexe en une seule fois. __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces étapes intermédiaires__: s'il faut éviter de faire de très longues étapes (sinon l'évaluation différée plante), il faut également éviter d'exécuter une à une les étapes du traitement (sinon on perd les avantages de l'évaluation différée). Il n'y a pas de solution miracle, et seule la pratique permet de déterminer ce qui est raisonnable. Voici toutefois quelques conseils de bon sens: @@ -405,9 +403,9 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): - les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; -- les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions. Par ailleurs, les deux `Arrow Table` doivent être parfaitement compatibles pour être empilés (il faut le même nombre de colonnes avec le même nom et le même type, ce qui n'est pas toujours le cas en pratique). +- les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions. Par ailleurs, les deux `Arrow Table` doivent être parfaitement compatibles pour être empilés (il faut le même nombre de colonnes avec le même nom et le même type, ce qui n'est pas toujours le cas en pratique). - ```{r eval=FALSE,message=FALSE} + ```{r eval=FALSE, message=FALSE} # Comment empiler de multiples Arrow Tables resultats <- table1 |> union(table2) |> From e8f6c134ef71e402f790e67004293609be6fea82 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 14:04:57 +0100 Subject: [PATCH 45/92] =?UTF-8?q?R=C3=A9f=C3=A9rences?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 4bee4dbd..6e1058a5 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -532,5 +532,6 @@ Si les pistes mentionnées précédemment ne fournissent pas de solution simple, ## Pour en savoir plus {#RessourcesArrow} - la documentation officielle du _package_ [`arrow`](https://arrow.apache.org/docs/dev/r/index.html) (en anglais); -- [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); +- [un post de blog qui décrit en détail les liens entre `libarrow` et `R`](https://blog.djnavarro.net/posts/2022-01-18_binding-arrow-to-r/) (en anglais); +- la [liste](https://arrow.apache.org/docs/dev/r/reference/acero.html) des fonctions du _tidyverse_ supportées par `acero`. From 0bfb6f9edaad1d6eda4b602f25a73b2de7bf58fc Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 24 Jan 2024 14:27:22 +0100 Subject: [PATCH 46/92] Ajout sur duckdb --- 03_Fiches_thematiques/Fiche_arrow.qmd | 42 +++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 6e1058a5..adc70300 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -398,11 +398,24 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é - __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. - __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème, car ces opérations sont simples. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. -### Connaître les limites d'`arrow` +### Connaître les limites d'`arrow` {#sec-limites-arrow} -Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici trois limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): +Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici quatre limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): - les __jointures de tables volumineuses__: `arrow` ne parvient pas à joindre des tables de données très volumineuses; il est préférable d'utiliser `duckdb` pour ce type d'opération; +- les __réorganisations de données__ (_wide-to-long_ et _long-to-wide_): il n'existe pas à ce jour dans `arrow` de fonctions pour réorganiser une table de données (comme `pivot_wider` et `pivot_longer` du _package_ `tidyr`). +- les __fonctions fenêtre__ (_window functions_): `arrow` ne permet pas d'ajouter directement à une table des informations issues d'une agrégation par groupe de la même table. Par exemple, `arrow` ne peut pas ajouter directement à la base permanente des équipements une colonne égale au nombre total d'équipements du département: + + ```{r eval=FALSE, message=FALSE} + # Arrow ne peut pas exécuter ceci + data <- bpe_ens_2018_arrow |> + group_by(DEP) |> + mutate( + NB_EQUIP_TOTAL_DEP = sum(NB_EQUIP) + ) |> + compute() + ``` + - les __empilements de tables__: il est facile d'empiler plusieurs `tibbles` avec `dplyr` grâce à la fonction `bind_rows()`: `bind_rows(table1, table2, table3, table4)`. En revanche, il n'existe pas à ce jour de fonction similaire dans `arrow`. Les fonctions `union` et `union_all` permettent d'empiler seulement deux `Arrow Table`, donc pour empiler plusieurs `Arrow Tables` il faut appeler plusieurs fois ces fonctions. Par ailleurs, les deux `Arrow Table` doivent être parfaitement compatibles pour être empilés (il faut le même nombre de colonnes avec le même nom et le même type, ce qui n'est pas toujours le cas en pratique). ```{r eval=FALSE, message=FALSE} @@ -414,7 +427,6 @@ Le projet `arrow` est relativement récent et en développement actif. Il n'est compute() ``` -- les __réorganisations de données__ (_wide-to-long_ et _long-to-wide_): il n'existe pas à ce jour dans `arrow` de fonctions pour réorganiser une table de données (comme `pivot_wider` et `pivot_longer` du _package_ `tidyr`). ### Surmonter le problème des fonctions non supportées par `acero` @@ -455,6 +467,30 @@ resultats <- bpe_ens_2018_arrow |> compute() ``` +#### Passer par `duckdb` + +Il arrive qu'il ne soit pas possible de résoudre le problème en réécrivant légèrement le traitement. __Une autre solution peut consister à passer par `duckdb`, qui permet de manipuler directement des objets `Arrow Table` de façon simple et transparente.__ Dans l'exemple suivant, on veut ajouter à la base permanente des équipements une colonne égale au nombre total d'équipements du département. Cette opération ne peut pas être exécutée par `arrow` (voir le paragraphe @sec-limites-arrow), contrairement à `duckdb`. Voici comment faire: + +```{r eval=FALSE, message=FALSE} +library(duckdb) +# Arrow ne peut pas exécuter ceci +data <- bpe_ens_2018_arrow |> + to_duckdb() |> + group_by(DEP) |> + mutate( + NB_EQUIP_TOTAL_DEP = sum(NB_EQUIP) + ) |> + to_arrow() |> + compute() +``` + +Cet exemple appelle trois commentaires: + +- La fonction `to_duckdb()` sert à ce que `duckdb` puisse accéder à l'objet `Arrow Table`; +- Symétriquement, la fonction `to_arrow()` sert à remettre les données dans un objet `Arrow Table`; +- Les instructions figurant entre ces deux étapes (le `group_by()` puis le `summarise()`) sont exécutées par le moteur d'exécution de `duckdb`, de façon complètement transparente pour l'utilisateur. + + #### Définir soi-même des fonctions `arrow` (utilisation avancée) Si les pistes mentionnées précédemment ne fournissent pas de solution simple, il est possible d'aller plus loin et d'écrire ses propres fonctions `arrow`. Cette approche permet de faire beaucoup plus de choses mais elle nécessite de bien comprendre le fonctionnement d'`arrow` et les fonctions internes de la librairie `libarrow`. Il s'agit d'une utilisation avancée d'`arrow` qui dépasse le cadre de la documentation `utilitR`. Les lecteurs intéressés pourront consulter les deux ressources suivantes: From e78a140ba03ead9740107ba87cca065b1e655726 Mon Sep 17 00:00:00 2001 From: Lino Galiana Date: Wed, 24 Jan 2024 14:42:55 +0100 Subject: [PATCH 47/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Julien PRAMIL <100139338+jpramil@users.noreply.github.com> --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index adc70300..d3c4eed0 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -39,7 +39,7 @@ Un point important à retenir est donc que **`arrow` n'est pas un outil spécifi Le projet `arrow` présente cinq spécificités: -- __Représentation des données en mémoire__: `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient l'intégralité de cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. +- __Représentation des données en mémoire__ : `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient l'intégralité de cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. - __Utilisation avec Parquet__: `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. From e8a5bffbf652b12cdb065e58ecd61cda6f3e425c Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:30:58 +0100 Subject: [PATCH 48/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Julien PRAMIL <100139338+jpramil@users.noreply.github.com> --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d3c4eed0..bef89448 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -134,7 +134,7 @@ View(extrait_bpe) __Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), *comme si* cette table était un `data.frame` ou un `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. Il y a néanmoins des subtilités à connaître, détaillées dans la suite de cette fiche. -Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliqué plus loin, dans le paragraphe sur l'évaluation différée. +Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliquée plus loin, dans le paragraphe sur l'évaluation différée.
From 73c0a60a954c142021d6da5c25b657b8127ebea8 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:31:15 +0100 Subject: [PATCH 49/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Romain Lesur --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index bef89448..33e54780 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -74,7 +74,7 @@ Le _package_ `arrow` présente quatre caractéristiques importantes: - un moteur d'exécution spécifique: `acero`; - un mode de fonctionnement particulier: l'évaluation différée. -### Charger et paramétrer le `arrow` +### Charger et paramétrer le *package* `arrow` Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. From 1b3f4e477dac702f82b59a20ed18249fe70d7cec Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:31:45 +0100 Subject: [PATCH 50/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Romain Lesur --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 33e54780..6bf45f0e 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -177,7 +177,7 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table -__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puissent les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". +__Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puisse les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". ### L'évaluation différée avec `arrow` (_lazy evaluation_) {#sec-lazy} From c52ab9a0ac699acf7b5b100ae0fe1bbce406499d Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 24 Jan 2024 22:32:03 +0100 Subject: [PATCH 51/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Romain Lesur --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 6bf45f0e..9bf1ab2d 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -350,7 +350,7 @@ Voici quelques commentaires pour comprendre ce traitement: #### Quelles sont les limites de l'évaluation différée? L'évaluation différée optimise les performances en minimisant la quantité de données chargées en RAM et la quantité de calculs effectivement réalisés. -Avec cette vision en tête, on pourrait penser que la meilleure façon d'utiliser `arrow` est d'écrire un traitement entier en mode _lazy_ (autrement dit: sans aucun `compute()` ni aucun `collect()` dans les étapes intermédiaires), et faire un unique `compute()` ou `collect()` tout à la fin du traitement, pour que toutes les opérations soient réalisées de façon optimisée en une seule étape. Un traitement idéal ressemblerait alors à ceci: +Avec cette vision en tête, on pourrait penser que la meilleure façon d'utiliser `arrow` est d'écrire un traitement entier en mode _lazy_ (autrement dit, sans aucun `compute()` ni aucun `collect()` dans les étapes intermédiaires), et faire un unique `compute()` ou `collect()` tout à la fin du traitement, pour que toutes les opérations soient optimisées en une seule étape. Un traitement idéal ressemblerait alors à ceci: ```{r, eval=FALSE} # Se connecter aux données From a4838b0b5ecec229e9f7b2b447fbc59bb66b9fca Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Thu, 25 Jan 2024 10:20:54 +0100 Subject: [PATCH 52/92] Correction de coquilles --- 03_Fiches_thematiques/Fiche_arrow.qmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index adc70300..8c846cd4 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -214,9 +214,9 @@ __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler un - __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. - __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: -- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. +- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. -- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. +- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses.
@@ -469,11 +469,11 @@ resultats <- bpe_ens_2018_arrow |> #### Passer par `duckdb` -Il arrive qu'il ne soit pas possible de résoudre le problème en réécrivant légèrement le traitement. __Une autre solution peut consister à passer par `duckdb`, qui permet de manipuler directement des objets `Arrow Table` de façon simple et transparente.__ Dans l'exemple suivant, on veut ajouter à la base permanente des équipements une colonne égale au nombre total d'équipements du département. Cette opération ne peut pas être exécutée par `arrow` (voir le paragraphe @sec-limites-arrow), contrairement à `duckdb`. Voici comment faire: +Il arrive qu'il ne soit pas possible de résoudre le problème en réécrivant légèrement le traitement. __Une autre solution peut consister à passer par `duckdb`, qui permet de manipuler directement des objets `Arrow Table` de façon simple et transparente.__ Dans l'exemple suivant, on veut ajouter à la base permanente des équipements une colonne égale au nombre total d'équipements du département. Cette opération ne peut pas être exécutée par `arrow` (voir le paragraphe @sec-limites-arrow), contrairement à `duckdb`. Voici comment faire avec `duckdb`: ```{r eval=FALSE, message=FALSE} library(duckdb) -# Arrow ne peut pas exécuter ceci + data <- bpe_ens_2018_arrow |> to_duckdb() |> group_by(DEP) |> @@ -488,7 +488,7 @@ Cet exemple appelle trois commentaires: - La fonction `to_duckdb()` sert à ce que `duckdb` puisse accéder à l'objet `Arrow Table`; - Symétriquement, la fonction `to_arrow()` sert à remettre les données dans un objet `Arrow Table`; -- Les instructions figurant entre ces deux étapes (le `group_by()` puis le `summarise()`) sont exécutées par le moteur d'exécution de `duckdb`, de façon complètement transparente pour l'utilisateur. +- Les instructions figurant entre ces deux étapes (le `group_by()` puis le `mutate()`) sont exécutées par le moteur d'exécution de `duckdb`, de façon complètement transparente pour l'utilisateur. #### Définir soi-même des fonctions `arrow` (utilisation avancée) From f3a402e2a176ea6b7c2375f5735c890eb3ecf676 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:49:29 +0100 Subject: [PATCH 53/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 7c8e87ab..28bdd90c 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -2,7 +2,7 @@ ## Tâches concernées et recommandations -L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). +L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` par le biais de l'écosystème `Arrow` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-important} - Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); From 21b8f8a6b56e2a1bfcab4105a2851244981361d2 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:50:08 +0100 Subject: [PATCH 54/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 1 + 1 file changed, 1 insertion(+) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 28bdd90c..dada133d 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -5,6 +5,7 @@ L'utilisateur souhaite manipuler des données structurées sous forme de `data.frame` par le biais de l'écosystème `Arrow` (sélectionner des variables, sélectionner des observations, créer des variables, joindre des tables). ::: {.callout-important} +Tâches concernées et recommandations - Pour des tables de données de taille petite et moyenne (inférieure à 1 Go ou moins d'un million d'observations), il est recommandé d'utiliser les *packages* `tibble`, `dplyr` et `tidyr` qui sont présentés dans la fiche [Manipuler des données avec le `tidyverse`](#tidyverse); - Pour des tables de données de grande taille (plus de 1 Go en CSV, plus de 200 Mo en Parquet, ou plus d'un million d'observations), il est recommandé d'utiliser soit le *package* `data.table` qui fait l'objet de la fiche [Manipuler des données avec `data.table`](#datatable), soit le *package* `arrow` qui fait l'objet de la présente fiche, avec éventuellement `duckdb` en complément. From e43641427d26fd2acd24b167af2b38a23aeb040c Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:50:25 +0100 Subject: [PATCH 55/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index dada133d..ec94f631 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -29,7 +29,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est ### Qu'est-ce qu'`arrow`? -Apache `arrow` est un projet *open-source* qui propose deux choses: +[Apache `Arrow`](https://arrow.apache.org/) est un projet *open-source* qui propose deux choses: - **une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_**, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. - **une implémentation de ce standard en C++**, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. From effeb6b51c9855cf2568d8057b12a7125d60cb18 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:50:57 +0100 Subject: [PATCH 56/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index ec94f631..d270f59c 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -31,7 +31,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est [Apache `Arrow`](https://arrow.apache.org/) est un projet *open-source* qui propose deux choses: -- **une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_**, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. +- une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. - **une implémentation de ce standard en C++**, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. From adb1ce7a23bee964eb104876acad8f45388a097e Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:51:22 +0100 Subject: [PATCH 57/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d270f59c..d1fd759d 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -32,7 +32,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est [Apache `Arrow`](https://arrow.apache.org/) est un projet *open-source* qui propose deux choses: - une représentation standardisée des données tabulaires en mémoire vive appelée _Apache Arrow Columnar Format_, qui est à la fois efficace (les traitements sont rapides), interopérable (différents langages de programmation peuvent accéder aux mêmes données, sans conversion des données dans un autre format) et indépendante du langage de programmation utilisé. -- **une implémentation de ce standard en C++**, qui prend la forme d'une librairie C++ nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en Rust est par exemple utilisée par le projet `polars`. +- une implémentation de ce standard en `C++`, qui prend la forme d'une librairie `C++` nommée `libarrow`. Il existe d'autres implémentations dans d'autres langages; l'implémentation en `Rust` est par exemple utilisée par le projet [`Polars`](https://pola.rs/), une librairie alternative à `dplyr` (`R`) ou `Pandas` (`Python`) pour le traitement de données. Un point important à retenir est donc que **`arrow` n'est pas un outil spécifique à `R`**, et il faut bien distinguer le projet `arrow` (et la librairie C++ `libarrow`) du *package* `R` `arrow`. Ce *package* propose simplement une interface qui permet d'utiliser la librairie `libarrow` avec `R`, et il existe d'autres interfaces pour se servir de `libarrow` avec d'autres langages: en Python, en Java, en Javascript, en Julia, etc. From 5c0daaec590f88b6a4fb875ca62e8de045e34a76 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:52:30 +0100 Subject: [PATCH 58/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d1fd759d..63a08265 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -25,7 +25,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est - Il ne faut pas hésiter à demander de l'aide à des collègues, ou à poser des questions sur les salons Tchap adaptés (le salon Langage `R` par exemple). ::: -## Présentation des *packages* `arrow` et `duckdb` +## Présentation du package `arrow` et du projet associé ### Qu'est-ce qu'`arrow`? From e2749003eadbfa7001768bb929de05cd9abab0ca Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 26 Jan 2024 19:44:09 +0100 Subject: [PATCH 59/92] Remarque sur data.table --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 7c8e87ab..050968d6 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -63,7 +63,7 @@ En pratique, le *package* `arrow` présente trois avantages: - **Performances élevées**: `arrow` est très efficace et très rapide pour la manipulation de données tabulaires (nettement plus performant que `dplyr` par exemple); - **Usage réduit des ressources**: `arrow` est conçu pour ne charger en mémoire que le minimum de données. Cela permet de réduire considérablement les besoins en mémoire, même lorsque les données sont volumineuses; -- **Facilité d'apprentissage** grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. +- **Facilité d'apprentissage** grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. Il est à noter que le _package_ `data.table` n'est pas directement compatible avec `arrow`. ## Que faut-il savoir pour utiliser `arrow`? From 0b3b511a3e7f24c6760dc5392978573fded5f26f Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Fri, 26 Jan 2024 19:52:18 +0100 Subject: [PATCH 60/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 754c80a0..d22d4d25 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -274,7 +274,7 @@ write_parquet(res_final, "resultats.parquet") Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. ::: -### Accéder aux fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` +### Lire des fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` __Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: From 19f89ae1bfbb2cc15584eedcb17078867dd8d13b Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 26 Jan 2024 19:54:19 +0100 Subject: [PATCH 61/92] =?UTF-8?q?Pr=C3=A9ciser=20la=20recommandation=20Arr?= =?UTF-8?q?ow=20Table=20versus=20data.frames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 754c80a0..996598e9 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -208,9 +208,9 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? -### Utiliser des objets `Arrow Table` plutôt que des `tibbles` +### Utiliser des objets `Arrow Table` plutôt que des `data.frames` -__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `tibbles`__. Cela implique deux recommandations: +__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `data.frames` (ou des `tibbles`)__. Cela implique deux recommandations: - __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. - __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: From c0b7e46f4f106bf376e05bed63d59f35a38d1832 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Fri, 26 Jan 2024 20:02:26 +0100 Subject: [PATCH 62/92] Ajout d'un conseil --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 709f35ed..0b55238d 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -435,6 +435,10 @@ __Lorsqu'on manipule des données avec `arrow`, il arrive fréquemment qu'on éc Le recours à cette solution de repli a pour conséquence de dégrader fortement les performances (car le moteur de `dplyr` est moins efficace qu'`acero`). __Il est donc préférable d'essayer de réécrire la partie du traitement qui pose problème avec des fonctions supportées par `acero`.__ Cela est particulièrement recommandé si les données manipulées sont volumineuses ou si le traitement concerné doit être exécuté fréquemment. +::: {.callout-conseil .icon} +Il arrive qu'il soit impossible de trouver une solution entièrement supportée par `acero`, ou que la solution soit vraiment trop complexe à écrire. Ce n'est pas une catastrophe: en dernier recours, on peut tout à fait convertir temporairement les données en `tibble` (avec `collect()`) et exécuter le traitement qui pose problème avec `dplyr`. Le traitement sera simplement plus lent (voire beaucoup plus lent). En revanche, il est important de reconvertir ensuite les données en `Arrow Table` le plus vite possible, en utilisant la fonction `as_arrow_table()`. +::: + #### Une solution simple existe-t-elle? Dans la plupart des cas, il est possible de trouver une solution simple pour écrire un traitement que le moteur `acero` peut exécuter. Voici quelques pistes: From 88cadc86368a84a004038d1e20673533cb3e8845 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Sun, 28 Jan 2024 19:54:04 +0100 Subject: [PATCH 63/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 0b55238d..27c0cf85 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -44,7 +44,7 @@ Le projet `arrow` présente cinq spécificités: - __Utilisation avec Parquet__: `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. -- __Traitement de données volumineuses__: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données très volumineuses, plus grosses que la mémoire vive dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). +- __Traitement de données volumineuses__: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données plus volumineuses que la mémoire vive (RAM) dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). - __Interopérabilité__: `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. From 06153d1a2f841ae997d03e338cb75f35b7fa7448 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 19:55:41 +0100 Subject: [PATCH 64/92] Lien vers la section @sec-lazy --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 0b55238d..20f23677 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -48,7 +48,7 @@ Le projet `arrow` présente cinq spécificités: - __Interopérabilité__: `arrow` est conçu pour être interopérable entre plusieurs langages de programmation tels que `R`, Python, Java, C++, etc. Cela signifie que les données peuvent être échangées entre ces langages sans avoir besoin de convertir les données, d'où des gains importants de temps et de performance. -- __*Lazy Evaluation*__: `arrow` prend en charge la *lazy evaluation* (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. +- __*Lazy Evaluation*__: `arrow` prend en charge la *lazy evaluation* (évaluation différée) dans certains contextes. Cela signifie que les traitements ne sont effectivement exécutés que lorsqu'ils sont nécessaires, ce qui peut améliorer les performances en évitant le calcul de résultats intermédiaires non utilisés. La @sec-lazy présente en détail cette notion. ### A quoi sert le *package* `arrow`? @@ -181,7 +181,7 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table __Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puisse les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". -### L'évaluation différée avec `arrow` (_lazy evaluation_) {#sec-lazy} +### L'évaluation différée avec `arrow` (_lazy evaluation_) {#@sec-lazy} __Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de mémoriser les instructions, sans faire aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. From c2be8b633c3e8bbbbd7ef63d3244b40d72b2ebb8 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 19:59:19 +0100 Subject: [PATCH 65/92] =?UTF-8?q?Compl=C3=A9ment=20sur=20data.table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 20f23677..d5815a01 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -64,7 +64,7 @@ En pratique, le *package* `arrow` présente trois avantages: - **Performances élevées**: `arrow` est très efficace et très rapide pour la manipulation de données tabulaires (nettement plus performant que `dplyr` par exemple); - **Usage réduit des ressources**: `arrow` est conçu pour ne charger en mémoire que le minimum de données. Cela permet de réduire considérablement les besoins en mémoire, même lorsque les données sont volumineuses; -- **Facilité d'apprentissage** grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. Il est à noter que le _package_ `data.table` n'est pas directement compatible avec `arrow`. +- **Facilité d'apprentissage** grâce aux approches `dplyr` et SQL: `arrow` peut être utilisé avec les verbes de `dplyr` (`select`, `mutate`, etc.) et/ou avec le langage SQL grâce à `duckdb`. Par conséquent, il n'est pas nécessaire d'apprendre une nouvelle syntaxe pour utiliser `arrow`, on peut s'appuyer sur la ou les approches que l'on maîtrise déjà. En revanche, il est à noter que le _package_ `data.table` n'est pas directement compatible avec `arrow` (il faut convertir les objets `Arrow Table` en `data.table`, opération longue lorsque les données sont volumineuses). ## Que faut-il savoir pour utiliser `arrow`? From d13f4da075b8ddc861bef59aa7b9fd7ff36fac92 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:02:29 +0100 Subject: [PATCH 66/92] Ajouter un lien --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d5815a01..03162f17 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -27,7 +27,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est ## Présentation du package `arrow` et du projet associé -### Qu'est-ce qu'`arrow`? +### Qu'est-ce qu'`arrow`? {#@sec-presentation} [Apache `Arrow`](https://arrow.apache.org/) est un projet *open-source* qui propose deux choses: @@ -91,7 +91,7 @@ arrow::set_cpu_count(parallel::detectCores() %/% 2) ### Le `data.frame` version `arrow`: le `Arrow Table` -**Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la présentation d'`arrow` ci-dessus). Pour convertir un `data.frame` ou un `tibble` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. +**Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la [présentation d'`arrow`](@sec-presentation)). Pour convertir un `data.frame` ou un `tibble` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. Par rapport à un `data.frame` standard ou à un `tibble`, le `Arrow Table` se distingue immédiatement sur trois points. Pour illustrer ces différences, on utilise la base permanente des équipements 2018 (table `bpe_ens_2018`), transformée en `tibble` d'une part, et en `Arrow Table` d'autre part. From 773b63f31b55e56c44e8c28098eb36e55749049c Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:04:25 +0100 Subject: [PATCH 67/92] =?UTF-8?q?Remplacer=20les=20bo=C3=AEtes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 514dd9f7..db2ac7d3 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -121,7 +121,7 @@ bpe_ens_2018_arrow Troisième différence: alors qu'il est possible d'afficher le contenu d'un `data.frame` ou d'un `tibble` en cliquant sur son nom dans la rubrique `Data` de l'environnement ou en utilisant la fonction `View()`, il n'est pas possible d'afficher directement le contenu d'un `Arrow Table`. Pour afficher le contenu d'un `Arrow Table`, il faut d'abord convertir le `Arrow Table` en `tibble` avec la fonction `collect()`. -::: {.callout-conseil .icon} +::: {.callout-tip} Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` peut poser de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. **Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.** Voici un exemple de code qui le fait: ```{r, eval=FALSE} @@ -270,7 +270,7 @@ write_parquet(res_final, "resultats.parquet")
-::: {.callout-conseil .icon} +::: {.callout-tip} Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. ::: @@ -435,7 +435,7 @@ __Lorsqu'on manipule des données avec `arrow`, il arrive fréquemment qu'on éc Le recours à cette solution de repli a pour conséquence de dégrader fortement les performances (car le moteur de `dplyr` est moins efficace qu'`acero`). __Il est donc préférable d'essayer de réécrire la partie du traitement qui pose problème avec des fonctions supportées par `acero`.__ Cela est particulièrement recommandé si les données manipulées sont volumineuses ou si le traitement concerné doit être exécuté fréquemment. -::: {.callout-conseil .icon} +::: {.callout-tip} Il arrive qu'il soit impossible de trouver une solution entièrement supportée par `acero`, ou que la solution soit vraiment trop complexe à écrire. Ce n'est pas une catastrophe: en dernier recours, on peut tout à fait convertir temporairement les données en `tibble` (avec `collect()`) et exécuter le traitement qui pose problème avec `dplyr`. Le traitement sera simplement plus lent (voire beaucoup plus lent). En revanche, il est important de reconvertir ensuite les données en `Arrow Table` le plus vite possible, en utilisant la fonction `as_arrow_table()`. ::: From 3855b06d3ff9b897185235510babf07d0e508069 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Sun, 28 Jan 2024 20:07:03 +0100 Subject: [PATCH 68/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 514dd9f7..be4bbb91 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -133,7 +133,9 @@ View(extrait_bpe) ### Manipuler des `Arrow Table` avec la syntaxe `dplyr` -__Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), *comme si* cette table était un `data.frame` ou un `tibble` standard.__ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. Il y a néanmoins des subtilités à connaître, détaillées dans la suite de cette fiche. +Le _package_ `R` `arrow` a été écrit de façon à ce qu'un `Arrow Table` puisse être manipulé avec les fonctions de `dplyr` (`select`, `filter`, `mutate`, `left_join`, etc.), *comme si* cette table était un `data.frame` ou un `tibble` standard. + +Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de fonctions des _packages_ du `tidyverse` (comme `stringr` et `lubridate`). Cela s'avère très commode en pratique, car lorsqu'on sait utiliser `dplyr` et le `tidyverse`, on peut commencer à utiliser `arrow` sans avoir à apprendre une nouvelle syntaxe de manipulation de données. Il y a néanmoins des subtilités à connaître, détaillées dans la suite de cette fiche. Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliquée plus loin, dans le paragraphe sur l'évaluation différée. From cbd2c23bfc714a58371e080b1bba395543944efc Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:14:00 +0100 Subject: [PATCH 69/92] Section --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index db2ac7d3..f17b1f55 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -27,7 +27,7 @@ Apprendre à utiliser `arrow` n'est pas difficile, car la syntaxe utilisée est ## Présentation du package `arrow` et du projet associé -### Qu'est-ce qu'`arrow`? {#@sec-presentation} +### Qu'est-ce qu'`arrow`? {#sec-presentation} [Apache `Arrow`](https://arrow.apache.org/) est un projet *open-source* qui propose deux choses: @@ -181,7 +181,7 @@ __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table __Cette différence de moteurs d'exécution a une conséquence technique importante__: une fois que l'utilisateur a défini des instructions avec la syntaxe `dplyr`, il est nécessaire que celles-ci soient converties pour que le moteur `acero` (écrit en C++ et non en `R`) puisse les exécuter. De façon générale, `arrow` fait cette conversion de façon automatique et invisible, car le _package_ `arrow` contient la traduction C++ de plusieurs centaines de fonctions du `tidyverse`. Par exemple, le _package_ `arrow` contient la traduction C++ de la fonction `filter()` de `dplyr`, ce qui fait que les instructions `filter()` écrites en syntaxe `tidyverse` sont converties de façon automatique et invisible en des instructions C++ équivalentes. La liste des fonctions du _tidyverse_ supportées par `acero` est disponible sur [cette page](https://arrow.apache.org/docs/dev/r/reference/acero.html). Il arrive toutefois qu'on veuille utiliser une fonction non supportée par `acero`. Cette situation est décrite dans le paragraphe "Comment utiliser une fonction non supportée par `acero`". -### L'évaluation différée avec `arrow` (_lazy evaluation_) {#@sec-lazy} +### L'évaluation différée avec `arrow` (_lazy evaluation_) {#sec-lazy} __Une caractéristique importante d'`arrow` est qu'il pratique l'évaluation différée (_lazy evaluation_): les calculs ne sont effectivement réalisés que lorsqu'ils sont nécessaires__. En pratique, cela signifie qu'`arrow` se contente de mémoriser les instructions, sans faire aucun calcul tant que l'utilisateur ne le demande pas explicitement. Il existe deux fonctions pour déclencher l'évaluation d'un traitement `arrow`: `collect()` et `compute()`. Il n'y a qu'une seule différence entre `collect()` et `compute()`, mais elle est importante: `collect()` renvoie le résultat du traitement sous la forme d'un `tibble`, tandis que `compute()` le renvoie sous la forme d'un `Arrow Table`. From 0670d05a55ae35c7ac425c55bd387519280afb14 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:20:02 +0100 Subject: [PATCH 70/92] Ajouter une partie --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index b739d8c1..b9d72b17 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -401,6 +401,9 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é - __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. - __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème, car ces opérations sont simples. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. + +## Notions avancées + ### Connaître les limites d'`arrow` {#sec-limites-arrow} Le projet `arrow` est relativement récent et en développement actif. Il n'est donc pas surprenant qu'il y ait parfois des bugs, et que certaines fonctions standards de `R` ne soient pas encore disponibles en `arrow`. Il est important de connaître les quelques limites d'`arrow` pour savoir comment les contourner. Voici quatre limites d'`arrow` à la date de rédaction de cette fiche (janvier 2024): From 2fd202318bf187915f1dfe0582f5245ce2783345 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:32:21 +0100 Subject: [PATCH 71/92] Supprimer un mot redondant --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index b9d72b17..147fe1b5 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -286,7 +286,7 @@ __Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` p ### Savoir bien utiliser l'évaluation différée -Le paragraphe @sec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. +La @sec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. ```{r, message=FALSE} # Sauvegarder la BPE 2018 sous la forme d'un dataset Arrow partitionné From 293289605e6318c590f70cfbff0326383752a8b0 Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:35:13 +0100 Subject: [PATCH 72/92] =?UTF-8?q?Compl=C3=A9ment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 147fe1b5..1f67fe16 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -336,7 +336,7 @@ Voici quelques commentaires pour comprendre ce traitement: show_exec_plan(ds_bpe2018) ``` - + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses. Premièrement, elle contient la première requête, mais elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). Deuxièmement, on retrouve tous les éléments du traitement (notamment le `group_by` et la somme), mais le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). + + La deuxième requête est un peu plus longue, et si on regarde en détail, on constate deux choses. Premièrement, elle contient la première requête, mais elle n'a conservé que les variables utilisées dans le traitement (`NB_EQUIP` et `DEP`). C'est un exemple d'optimisation faite par `arrow`: le moteur `acero` a compris automatiquement qu'il suffisait de charger seulement deux variables pour réaliser le traitement. Deuxièmement, on retrouve tous les éléments du traitement (notamment le `group_by` et la somme), mais le traitement décrit en syntaxe `tidyverse` a été traduit automatiquement en fonctions internes d'`arrow` (la fonction `sum` est par exemple remplacée par `hash_sum`). ```{r, message=FALSE} # Imprimer la deuxième requête, qui contient la première From 3887d0981ae6bf78b1b68777c74f572392b239ca Mon Sep 17 00:00:00 2001 From: Olivier Meslin Date: Sun, 28 Jan 2024 20:37:09 +0100 Subject: [PATCH 73/92] =?UTF-8?q?D=C3=A9placer=20la=20partie=20lazy=20eval?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 146 +++++++++++++------------- 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 1f67fe16..8170ec8f 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -210,80 +210,6 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? -### Utiliser des objets `Arrow Table` plutôt que des `data.frames` - -__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `data.frames` (ou des `tibbles`)__. Cela implique deux recommandations: - -- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. -- __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: - -- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. - -- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. - -
- - - - - - - - - - -
__Situation à éviter__: `collect()` dans les étapes intermédiaires __Usage recommandé__: `compute()` dans les étapes intermédiaires
-```{r eval=FALSE,message=FALSE} -# Etape 1 -res_intermediaire1 <- bpe_ens_2018_tbl |> - group_by(DEP) |> - summarise( - NB_EQUIP_TOT = sum(NB_EQUIP) - ) |> - collect() - -# Etape 2 -res_final <- res_intermediaire1 |> - filter(DEP == "59") |> - collect() - -# Sauvegarder les résultats -write_parquet(res_final, "resultats.parquet") -``` - -```{r eval=FALSE,message=FALSE} -# Etape 1 -res_intermediaire2 <- bpe_ens_2018_tbl |> - group_by(DEP) |> - summarise( - NB_EQUIP_TOT = sum(NB_EQUIP) - ) |> - compute() - -# Etape 2 -res_final <- res_intermediaire2 |> - filter(DEP == "59") |> - compute() - -# Sauvegarder les résultats -write_parquet(res_final, "resultats.parquet") -``` -
- -
- -::: {.callout-tip} -Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. -::: - -### Lire des fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` - -__Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: - -- __Consommation mémoire inférieure__: la fonction `open_dataset()` crée une connexion au fichier Parquet, mais elle n'importe pas les données contenues dans le fichier tant que l'utilisateur ne le demande pas avec `compute()` ou `collect()`, et elle est optimisée pour importer uniquement les données nécessaires au traitement. Inversement, la fonction `read_parquet()` importe immédiatement dans `R` toutes les données du fichier Parquet, y compris des données qui ne servent pas à la suite du traitement. -- __Usage plus général__: la fonction `open_dataset()` peut se connecter à un fichier Parquet unique, mais aussi à des fichiers Parquet partitionnés, tandis que `read_parquet()` ne peut pas lire ces derniers. - - ### Savoir bien utiliser l'évaluation différée La @sec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. @@ -401,6 +327,78 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é - __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. - __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème, car ces opérations sont simples. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. +### Utiliser des objets `Arrow Table` plutôt que des `data.frames` + +__Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `data.frames` (ou des `tibbles`)__. Cela implique deux recommandations: + +- __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. +- __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: + +- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. + +- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. + +
+ + + + + + + + + + +
__Situation à éviter__: `collect()` dans les étapes intermédiaires __Usage recommandé__: `compute()` dans les étapes intermédiaires
+```{r eval=FALSE,message=FALSE} +# Etape 1 +res_intermediaire1 <- bpe_ens_2018_tbl |> + group_by(DEP) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> + collect() + +# Etape 2 +res_final <- res_intermediaire1 |> + filter(DEP == "59") |> + collect() + +# Sauvegarder les résultats +write_parquet(res_final, "resultats.parquet") +``` + +```{r eval=FALSE,message=FALSE} +# Etape 1 +res_intermediaire2 <- bpe_ens_2018_tbl |> + group_by(DEP) |> + summarise( + NB_EQUIP_TOT = sum(NB_EQUIP) + ) |> + compute() + +# Etape 2 +res_final <- res_intermediaire2 |> + filter(DEP == "59") |> + compute() + +# Sauvegarder les résultats +write_parquet(res_final, "resultats.parquet") +``` +
+ +
+ +::: {.callout-tip} +Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. +::: + +### Lire des fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` + +__Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: + +- __Consommation mémoire inférieure__: la fonction `open_dataset()` crée une connexion au fichier Parquet, mais elle n'importe pas les données contenues dans le fichier tant que l'utilisateur ne le demande pas avec `compute()` ou `collect()`, et elle est optimisée pour importer uniquement les données nécessaires au traitement. Inversement, la fonction `read_parquet()` importe immédiatement dans `R` toutes les données du fichier Parquet, y compris des données qui ne servent pas à la suite du traitement. +- __Usage plus général__: la fonction `open_dataset()` peut se connecter à un fichier Parquet unique, mais aussi à des fichiers Parquet partitionnés, tandis que `read_parquet()` ne peut pas lire ces derniers. ## Notions avancées From 927ccdd78dc1048fe9a1f66933434a0fe97d4b4c Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:38:14 +0100 Subject: [PATCH 74/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 1 - 1 file changed, 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 8170ec8f..d272edcf 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -83,7 +83,6 @@ Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` library(arrow) library(dplyr) -# Autoriser arrow à utiliser plusieurs processeurs en parallèle options(arrow.use_threads = TRUE) # Définir le nombre de processeurs qu'arrow peut utiliser arrow::set_cpu_count(parallel::detectCores() %/% 2) From deac8874d65439822c00419ef60135437ee4b6ec Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:40:44 +0100 Subject: [PATCH 75/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd [skip-ci] Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index d272edcf..a916bee4 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -106,7 +106,7 @@ Première différence: alors que les `data.frames` et les `tibbles` apparaissent ![](../pics/arrow/diff_environnement.png) -Deuxième différence: alors que l'appel à un `data.frame` ou `tibble` en affiche les premières lignes, l'appel à un `Arrow Table` affiche uniquement des métadonnées (nombre de lignes et de colonnes, nom et type des colonnes). +Deuxième différence: alors que l'affichage dans la console d'un `data.frame` ou `tibble` permet de visualiser les premières lignes, la même opération sur un `Arrow Table` affiche uniquement des métadonnées (nombre de lignes et de colonnes, nom et type des colonnes). ```{r} # Affichage d'un tibble From 4b051c30ef8395f2ff37d0b12c968def711572c3 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:41:59 +0100 Subject: [PATCH 76/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index a916bee4..ae88d837 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -42,6 +42,14 @@ Le projet `arrow` présente cinq spécificités: - __Représentation des données en mémoire__ : `arrow` organise les données en colonnes plutôt qu'en lignes (on parle de *columnar format*). Concrètement, cela veut dire que dans la RAM toutes les valeurs de la première colonne sont stockées de façon contiguë, puis les valeurs de la deuxième colonne, etc. Cette structuration des données rend les traitements très efficaces: si l'on veut par exemple calculer la moyenne d'une variable, il est possible d'accéder directement au bloc de mémoire vive qui contient l'intégralité de cette colonne (indépendamment des autres colonnes de la table de données), d'où un traitement très rapide. +
+ +Illustration de ce principe + +![Illustration de ce principe du stockage orienté colonnes (droite) par rapport au csv](https://raw.githubusercontent.com/InseeFrLab/ssphub/news-janvier/infolettre/infolettre_17/parquet.png) +
+ + - __Utilisation avec Parquet__: `arrow` est souvent utilisé pour manipuler des données stockées en format Parquet. Parquet est un format de stockage orienté colonne conçu pour être très rapide en lecture (voir la fiche [Importer des fichiers Parquet](#importparquet) pour plus de détails). `arrow` est optimisé pour travailler sur des fichiers Parquet, notamment lorsqu'ils contiennent des données très volumineuses. - __Traitement de données volumineuses__: `arrow` est conçu pour traiter des données sans avoir besoin de les charger dans la mémoire vive. Cela signifie qu'`arrow` est capable de traiter des données plus volumineuses que la mémoire vive (RAM) dont on dispose. C'est un avantage majeur en comparaison aux autres approches possibles en `R` (`data.table` et `dplyr` par exemple). From 2dc7e4d6d491910c46a755a5ad90b6fcdf61a892 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:42:25 +0100 Subject: [PATCH 77/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd [skip-ci] Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index ae88d837..3f9685bf 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -91,7 +91,7 @@ Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` library(arrow) library(dplyr) -options(arrow.use_threads = TRUE) +options(arrow.use_threads = TRUE) # <1> # Définir le nombre de processeurs qu'arrow peut utiliser arrow::set_cpu_count(parallel::detectCores() %/% 2) ``` From 23439fd1f32b891622ded2c03215c23d27a65767 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:42:55 +0100 Subject: [PATCH 78/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd [skip-ci] Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 3f9685bf..ad8ce388 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -87,7 +87,8 @@ Le _package_ `arrow` présente quatre caractéristiques importantes: Pour utiliser `arrow`, il faut commencer par charger le *package*. Comme `arrow` s'utilise presque toujours avec `dplyr` en pratique, il est préférable de prendre l'habitude de charger les deux *packages* ensemble. Par ailleurs, il est utile de définir systématiquement deux réglages qui sont importants pour les performances d'`arrow`: autoriser `arrow` à utiliser plusieurs processeurs en parallèle, et définir le nombre de processeurs qu'`arrow` peut utiliser. -```{r, message=FALSE, warning=FALSE} +```{r} +#| output: false library(arrow) library(dplyr) From b783d5876e0d25ccc06dcea367023568eebaa0fd Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:43:19 +0100 Subject: [PATCH 79/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index ad8ce388..f3cfa3b5 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -96,7 +96,8 @@ options(arrow.use_threads = TRUE) # <1> # Définir le nombre de processeurs qu'arrow peut utiliser arrow::set_cpu_count(parallel::detectCores() %/% 2) ``` - +1. Autoriser `arrow` à utiliser plusieurs processeurs en parallèle +2. Définir le nombre de processeurs qu'arrow peut utiliser ### Le `data.frame` version `arrow`: le `Arrow Table` **Le *package* `arrow` structure les données non pas dans un `data.frame` classique, mais dans un objet spécifique à `arrow`: le `Arrow Table`.** Dans un objet `Arrow Table`, les données sont organisées en colonnes plutôt qu'en lignes, conformément aux spécifications d'`arrow` (voir la [présentation d'`arrow`](@sec-presentation)). Pour convertir un `data.frame` ou un `tibble` en `Arrow Table`, il suffit d'utiliser la fonction `as_arrow_table()`. From 6b4697ec1595aca8fa49ea9bd9e6f652af44e6a4 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:43:33 +0100 Subject: [PATCH 80/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 1 - 1 file changed, 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index f3cfa3b5..13043776 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -93,7 +93,6 @@ library(arrow) library(dplyr) options(arrow.use_threads = TRUE) # <1> -# Définir le nombre de processeurs qu'arrow peut utiliser arrow::set_cpu_count(parallel::detectCores() %/% 2) ``` 1. Autoriser `arrow` à utiliser plusieurs processeurs en parallèle From a44f8fc06a082cf11b744fdd104d8a90f449ac56 Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:44:04 +0100 Subject: [PATCH 81/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd [skip-ci] Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 13043776..217ed89c 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -130,7 +130,8 @@ bpe_ens_2018_arrow Troisième différence: alors qu'il est possible d'afficher le contenu d'un `data.frame` ou d'un `tibble` en cliquant sur son nom dans la rubrique `Data` de l'environnement ou en utilisant la fonction `View()`, il n'est pas possible d'afficher directement le contenu d'un `Arrow Table`. Pour afficher le contenu d'un `Arrow Table`, il faut d'abord convertir le `Arrow Table` en `tibble` avec la fonction `collect()`. ::: {.callout-tip} -Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` peut poser de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. **Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.** Voici un exemple de code qui le fait: +Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` peut poser de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. **Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.** + ```{r, eval=FALSE} # Extraire les 1000 premières lignes du Arrow Table et les convertir en tibble From c9571bcf974633caf5401ddf46503b13c7a25b0f Mon Sep 17 00:00:00 2001 From: Olivier Meslin <44379737+oliviermeslin@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:45:15 +0100 Subject: [PATCH 82/92] Update 03_Fiches_thematiques/Fiche_arrow.qmd [skip-ci] Co-authored-by: Lino Galiana --- 03_Fiches_thematiques/Fiche_arrow.qmd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 217ed89c..98a7ac26 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -133,7 +133,10 @@ Troisième différence: alors qu'il est possible d'afficher le contenu d'un `dat Il arrive fréquemment que l'on souhaite jeter un coup d'oeil au contenu d'un `Arrow Table`. Toutefois, convertir directement un `Arrow Table` très volumineux en `tibble` peut poser de sérieux problèmes: temps de conversion, consommation importante de RAM, voire plantage de `R` si le `Arrow Table` est vraiment très gros. **Il est donc fortement conseillé de prendre un petit extrait du `Arrow Table` concerné et de convertir uniquement cet extrait en `tibble`.** -```{r, eval=FALSE} +```{r} +#| eval: false +#| code-fold: true +#| code-summary: Exemple de code qui visualise un échantillon d'une table Arrow # Extraire les 1000 premières lignes du Arrow Table et les convertir en tibble extrait_bpe <- bpe_ens_2018_arrow |> slice_head(n = 1000) |> collect() View(extrait_bpe) From 90390919c27b3942c3c1785d09dafe82631b05b2 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 09:50:50 +0100 Subject: [PATCH 83/92] Ajouter une intro dans un paragraphe [skip-ci] --- 03_Fiches_thematiques/Fiche_arrow.qmd | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 217ed89c..5f89e0f1 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -219,6 +219,15 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? +Au premier abord, on peut avoir l'impression qu'`arrow` s'utilise exactement comme `dplyr` (c'est d'ailleurs fait exprès!). Il y a toutefois quelques différences qui peuvent avoir un impact considérable sur les performances des traitements. Cette partie détaille trois recommandations à suivre pour bien utiliser `arrow`: + +- Utiliser correctement l'évaluation différée; +- Utiliser `compute()` plutôt que `collect()`; +- Utiliser `open_dataset()` plutôt que `read_parquet()`. + + + + ### Savoir bien utiliser l'évaluation différée La @sec-lazy a présenté la notion d'évaluation différée et son intérêt pour optimiser les performances. Toutefois, l'évaluation différée n'est pas toujours facile à utiliser, et présente des limites qu'il faut bien comprendre. Cette section décrit plus en détail le fonctionnement de l'évaluation différée et ses limites. Pour illustrer ce fonctionnement, on commence par exporter la base permanente des équipements sous la forme d'un dataset Arrow partitionné. La fiche [Importer des fichiers Parquet](#importparquet) décrit en détail ce qu'est un fichier Parquet partitionné et comment le manipuler. From e2af7db34d2f005c9ac793a49e6fd5e30af352a3 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 10:15:12 +0100 Subject: [PATCH 84/92] =?UTF-8?q?Am=C3=A9liorer=20un=20tableau?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 5f89e0f1..68a3b625 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -148,14 +148,12 @@ Il est également possible d'utiliser sur un `Arrow Table` un certain nombre de Dans l'exemple suivant, on calcule le nombre d'équipements par région, à partir d'un `tibble` et à partir d'un `Arrow table`. La seule différence apparente entre les deux traitement est la présence de la fonction `collect()` à la fin des instructions; cette fonction indique que l'on souhaite que le résultat du traitement soit stocké sous la forme d'un `tibble`. La raison d'être de ce `collect()` est expliquée plus loin, dans le paragraphe sur l'évaluation différée. -
+:::: {.columns} + +::: {.column width="49%"} + +Manipulation d'un `tibble` - - - - - - - - -
Manipulation d'un `tibble`Manipulation d'un `Arrow Table`
```{r eval=FALSE,message=FALSE} bpe_ens_2018_tbl |> group_by(REG) |> @@ -163,8 +161,17 @@ bpe_ens_2018_tbl |> NB_EQUIP_TOT = sum(NB_EQUIP) ) ``` - + +::: + +::: {.column width="2%"} + +::: + +::: {.column width="49%"} + +Manipulation d'un `Arrow Table` + ```{r eval=FALSE,message=FALSE} bpe_ens_2018_arrow |> group_by(REG) |> @@ -173,12 +180,10 @@ bpe_ens_2018_arrow |> ) |> collect() ``` -
-
+::: +:::: ### Le moteur d'exécution d'`arrow`: `acero` From d0ea26495f56c55614816e2fef14e43c213818f3 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 11:32:13 +0100 Subject: [PATCH 85/92] Gras [skip-ci] --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 7654118b..3dcc7381 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -155,7 +155,7 @@ Dans l'exemple suivant, on calcule le nombre d'équipements par région, à part ::: {.column width="49%"} -Manipulation d'un `tibble` +__Manipulation d'un `tibble`__ ```{r eval=FALSE,message=FALSE} bpe_ens_2018_tbl |> @@ -173,7 +173,7 @@ bpe_ens_2018_tbl |> ::: {.column width="49%"} -Manipulation d'un `Arrow Table` +__Manipulation d'un `Arrow Table`__ ```{r eval=FALSE,message=FALSE} bpe_ens_2018_arrow |> From 6b01aadb033a19ea4878d443ea85b99b9dd0a705 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 11:40:13 +0100 Subject: [PATCH 86/92] =?UTF-8?q?Am=C3=A9liorer=20les=20tableaux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 46 +++++++++++++++------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 3dcc7381..c9290957 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -360,22 +360,17 @@ __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler un - __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. - __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: -- __Situation à éviter__: la première étape de traitement étant déclenchée par `collect()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire1` est un `tibble`. Par conséquent, c'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_intermediaire1` lors de la seconde étape du traitement, ce qui peut dégrader fortement les performances, en particulier si les données sont volumineuses. +:::: {.columns} + +::: {.column width="49%"} -- __Usage recommandé__: la première étape de traitement étant déclenchée par `compute()` (ligne 7 de l'exemple ci-dessous), la table intermédiaire `res_intermediaire2` est un `Arrow Table`. Par conséquent, c'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_intermediaire2` lors de la seconde étape du traitement, ce qui assure de bonnes performances notamment sur données volumineuses. +__Situation à éviter__ -
+La première étape de traitement est déclenchée par `collect()`, la table intermédiaire `res_etape1` est donc un `tibble`. C'est le moteur d'exécution de `dplyr` qui est utilisé pour manipuler `res_etape1` lors de la seconde étape, ce qui dégrade fortement les performances sur données volumineuses. - - - - - - - - - -
__Situation à éviter__: `collect()` dans les étapes intermédiaires __Usage recommandé__: `compute()` dans les étapes intermédiaires
```{r eval=FALSE,message=FALSE} # Etape 1 -res_intermediaire1 <- bpe_ens_2018_tbl |> +res_etape1 <- bpe_ens_2018_tbl |> group_by(DEP) |> summarise( NB_EQUIP_TOT = sum(NB_EQUIP) @@ -383,18 +378,30 @@ res_intermediaire1 <- bpe_ens_2018_tbl |> collect() # Etape 2 -res_final <- res_intermediaire1 |> +res_final <- res_etape1 |> filter(DEP == "59") |> collect() # Sauvegarder les résultats write_parquet(res_final, "resultats.parquet") ``` - + +::: + +::: {.column width="2%"} + +::: + +::: {.column width="49%"} + +__Usage recommandé__ + +La première étape de traitement est déclenchée par `compute()`, la table intermédiaire `res_etape1` est donc un `Arrow Table`. C'est le moteur d'exécution `acero` qui est utilisé pour manipuler `res_etape1` lors de la seconde étape, ce qui assure de bonnes performances notamment sur données volumineuses. + + ```{r eval=FALSE,message=FALSE} # Etape 1 -res_intermediaire2 <- bpe_ens_2018_tbl |> +res_etape1 <- bpe_ens_2018_tbl |> group_by(DEP) |> summarise( NB_EQUIP_TOT = sum(NB_EQUIP) @@ -402,18 +409,17 @@ res_intermediaire2 <- bpe_ens_2018_tbl |> compute() # Etape 2 -res_final <- res_intermediaire2 |> +res_final <- res_etape1 |> filter(DEP == "59") |> compute() # Sauvegarder les résultats write_parquet(res_final, "resultats.parquet") ``` -
-
+::: + +:::: ::: {.callout-tip} Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. From 4be20eff3fbda23a573a398ad2dc1639d69d0107 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 11:41:57 +0100 Subject: [PATCH 87/92] Bullet points --- 03_Fiches_thematiques/Fiche_arrow.qmd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index c9290957..1f8bf90c 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -190,7 +190,10 @@ bpe_ens_2018_arrow |> ### Le moteur d'exécution d'`arrow`: `acero` -Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibble` et manipuler un `Arrow Table`. Pour bien la comprendre, il faut d'abord comprendre la __distinction entre syntaxe de manipulation des données et moteur d'exécution__. La syntaxe de manipulation des données sert à décrire les manipulations de données qu'on veut faire (calculer des moyennes, faire des jointures...), indépendamment de la façon dont ces calculs sont effectivement réalisés. Inversement, le moteur d'exécution fait référence à la façon dont les opérations sur les données sont effectivement réalisées en mémoire, indépendamment de la façon dont elles ont été décrites par l'utilisateur. +Il y a une différence fondamentale entre manipuler un `data.frame` ou un `tibble` et manipuler un `Arrow Table`. Pour bien la comprendre, il faut d'abord comprendre la __distinction entre syntaxe de manipulation des données et moteur d'exécution__: + +- La syntaxe de manipulation des données sert à décrire les manipulations de données qu'on veut faire (calculer des moyennes, faire des jointures...), indépendamment de la façon dont ces calculs sont effectivement réalisés; +- le moteur d'exécution fait référence à la façon dont les opérations sur les données sont effectivement réalisées en mémoire, indépendamment de la façon dont elles ont été décrites par l'utilisateur. __La grande différence entre manipuler un `tibble` et manipuler un `Arrow Table` tient au moteur d'exécution__: si on manipule un `tibble` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution de `dplyr` qui fait les calculs; si on manipule un `Arrow Table` avec la syntaxe de `dplyr`, alors c'est le moteur d'exécution d'`arrow` (nommé `acero`) qui fait les calculs. C'est justement parce que le moteur d'exécution d'`arrow` est beaucoup plus efficace que celui de `dplyr` qu'`arrow` est beaucoup plus rapide. From 01b34af0767d7a47c9b61e7c0ef1aad10ade7802 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 11:52:26 +0100 Subject: [PATCH 88/92] Test --- 03_Fiches_thematiques/Fiche_arrow.qmd | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 1f8bf90c..19277426 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -361,7 +361,9 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `data.frames` (ou des `tibbles`)__. Cela implique deux recommandations: - __Importer les données directement dans des `Arrow Table`, ou à défaut convertir en `Arrow Table` avec la fonction `as_arrow_table()`.__ Par exemple, lorsqu'on importe un fichier Parquet avec la fonction `read_parquet()` ou un fichier csv avec la fonction `read_csv_arrow()`, il est recommandé d'utiliser l'option `as_data_frame = FALSE` pour que les données soient importées sous forme de `Arrow Table`. -- __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: +- __Utiliser systématiquement `compute()` plutôt que `collect()` dans les étapes de calcul intermédiaires.__ Cette recommandation est particulièrement importante. + + L'exemple suivant explique pourquoi il est préférable d'utiliser `compute()` dans les étapes intermédiaires: :::: {.columns} From a59976457a9095d216e0c6887a072e027fd14397 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 12:06:06 +0100 Subject: [PATCH 89/92] Diverses bricoles --- 03_Fiches_thematiques/Fiche_arrow.qmd | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 19277426..1a75e2e7 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -230,13 +230,12 @@ On pourrait penser que, lorsqu'on exécute l'ensemble de ce traitement, `arrow` ## Comment bien utiliser `arrow`? -Au premier abord, on peut avoir l'impression qu'`arrow` s'utilise exactement comme `dplyr` (c'est d'ailleurs fait exprès!). Il y a toutefois quelques différences qui peuvent avoir un impact considérable sur les performances des traitements. Cette partie détaille trois recommandations à suivre pour bien utiliser `arrow`: +Au premier abord, on peut avoir l'impression qu'`arrow` s'utilise exactement comme `dplyr` (c'est d'ailleurs fait exprès!). Il y a toutefois quelques différences qui peuvent avoir un impact considérable sur les performances des traitements. Cette partie détaille quatre recommandations à suivre pour bien utiliser `arrow`: - Utiliser correctement l'évaluation différée; - Utiliser `compute()` plutôt que `collect()`; -- Utiliser `open_dataset()` plutôt que `read_parquet()`. - - +- Utiliser `open_dataset()` plutôt que `read_parquet()`; +- Surveiller la consommation de RAM de `R`. ### Savoir bien utiliser l'évaluation différée @@ -356,6 +355,13 @@ __La vraie difficulté consiste à savoir quelle est la bonne longueur de ces é - __Plus les données sont volumineuses, plus il faut être prudent avant de définir de longues étapes de traitement__. - __Plus les opérations unitaires sont complexes, plus les étapes doivent être courtes.__ Par exemple, si les opérations sont des `filter()` et des `select()`, il est possible d'en enchaîner un certain nombre en une seule étape de traitement sans aucun problème, car ces opérations sont simples. Inversement, une étape de traitement ne doit pas comprendre plus de trois ou quatre jointures (car les jointures sont des opérations complexes), en particulier si les tables sont volumineuses. +### Lire des fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` + +__Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: + +- __Consommation mémoire inférieure__: la fonction `open_dataset()` crée une connexion au fichier Parquet, mais elle n'importe pas les données contenues dans le fichier tant que l'utilisateur ne le demande pas avec `compute()` ou `collect()`, et elle est optimisée pour importer uniquement les données nécessaires au traitement. Inversement, la fonction `read_parquet()` importe immédiatement dans `R` toutes les données du fichier Parquet, y compris des données qui ne servent pas à la suite du traitement. +- __Usage plus général__: la fonction `open_dataset()` peut se connecter à un fichier Parquet unique, mais aussi à des fichiers Parquet partitionnés, tandis que `read_parquet()` ne peut pas lire ces derniers. + ### Utiliser des objets `Arrow Table` plutôt que des `data.frames` __Lorsqu'on manipule des données volumineuses, il est essentiel de manipuler uniquement des objets `Arrow Table`, plutôt que des `data.frames` (ou des `tibbles`)__. Cela implique deux recommandations: @@ -430,12 +436,16 @@ write_parquet(res_final, "resultats.parquet") Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibble`, il suffit d'exécuter `class(le_nom_de_ma_table)`. Si la table est un `Arrow Table`, vous obtiendrez ceci: `"Table" "ArrowTabular" "ArrowObject" "R6"`. Si elle est un `tibble`, vous obtiendrez `"tbl_df" "tbl" "data.frame"`. ::: -### Lire des fichiers Parquet avec `open_dataset()` plutôt que `read_parquet()` +### Surveiller la consommation de RAM de `R` + + +Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique sur la gestion de la RAM: lorsque `arrow` a utilisé temporairement une grande quantité de RAM pour réaliser un traitement, `R` ne libère pas automatiquement la RAM devenue inutile. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Par conséquent, + + +- Si on travaille sur des données volumineuses, il est important de surveiller fréquemment sa consommation de RAM pour s'assurer qu'elle n'est pas excessive; la fiche [Superviser sa session `R`]{#superviser-ressources}. +- Si la consommation de RAM devient très élevée, la seule solution semble être de redémarrer la session `R`. En pratique, redémarrer la session `R` ne fait pas perdre plus de quelques minutes, car grâce à `arrow` et Parquet le chargement des données est très rapide. -__Il est recommandé d'utiliser systématiquement la fonction `open_dataset()` plutôt que la fonction `read_parquet()` pour accéder à des données stockées en format Parquet.__ En effet, la fonction `open_dataset()` présente deux avantages: -- __Consommation mémoire inférieure__: la fonction `open_dataset()` crée une connexion au fichier Parquet, mais elle n'importe pas les données contenues dans le fichier tant que l'utilisateur ne le demande pas avec `compute()` ou `collect()`, et elle est optimisée pour importer uniquement les données nécessaires au traitement. Inversement, la fonction `read_parquet()` importe immédiatement dans `R` toutes les données du fichier Parquet, y compris des données qui ne servent pas à la suite du traitement. -- __Usage plus général__: la fonction `open_dataset()` peut se connecter à un fichier Parquet unique, mais aussi à des fichiers Parquet partitionnés, tandis que `read_parquet()` ne peut pas lire ces derniers. ## Notions avancées From 26215464f4d3bd1636c8d31b54bc8dc0a0f4cc46 Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 13:01:24 +0100 Subject: [PATCH 90/92] =?UTF-8?q?Compl=C3=A9ments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index 1a75e2e7..e3e9927b 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -439,11 +439,11 @@ Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibbl ### Surveiller la consommation de RAM de `R` -Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique sur la gestion de la RAM: lorsque `arrow` a utilisé temporairement une grande quantité de RAM pour réaliser un traitement, `R` ne libère pas automatiquement la RAM devenue inutile. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Par conséquent, +Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique sur la gestion de la RAM: lorsque `arrow` a utilisé temporairement une grande quantité de RAM pour réaliser un traitement, `R` ne libère pas automatiquement la RAM devenue inutile. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Cette imperfection de la gestion de la RAM implique deux choses: -- Si on travaille sur des données volumineuses, il est important de surveiller fréquemment sa consommation de RAM pour s'assurer qu'elle n'est pas excessive; la fiche [Superviser sa session `R`]{#superviser-ressources}. -- Si la consommation de RAM devient très élevée, la seule solution semble être de redémarrer la session `R`. En pratique, redémarrer la session `R` ne fait pas perdre plus de quelques minutes, car grâce à `arrow` et Parquet le chargement des données est très rapide. +- Si on travaille sur des données volumineuses, __il est important de surveiller fréquemment sa consommation de RAM pour s'assurer qu'elle n'est pas excessive__; la fiche [Superviser sa session `R`]{#superviser-ressources}. +- Si la consommation de RAM devient très élevée, __la seule solution semble être de redémarrer la session `R`__. En pratique, redémarrer la session `R` ne fait pas perdre plus de quelques minutes, car grâce à `arrow` et Parquet le chargement des données est très rapide. From 36dbbdacc891c75373c8b2856225e2212927c43f Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 13:04:09 +0100 Subject: [PATCH 91/92] Formulation --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index e3e9927b..e97ba5a7 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -439,7 +439,7 @@ Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibbl ### Surveiller la consommation de RAM de `R` -Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique sur la gestion de la RAM: lorsque `arrow` a utilisé temporairement une grande quantité de RAM pour réaliser un traitement, `R` ne libère pas automatiquement la RAM devenue inutile. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Cette imperfection de la gestion de la RAM implique deux choses: +Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique que `R` n'a qu'un contrôle partiel sur la RAM occupé par `arrow`, et parvient pas toujours à libérer la RAM qu'`arrow` a utilisée temporairement pour réaliser un traitement. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Cette imperfection de la gestion de la RAM implique deux choses: - Si on travaille sur des données volumineuses, __il est important de surveiller fréquemment sa consommation de RAM pour s'assurer qu'elle n'est pas excessive__; la fiche [Superviser sa session `R`]{#superviser-ressources}. From 6aa5f2180c3e96002353a58cd5a7c6e624b646bb Mon Sep 17 00:00:00 2001 From: Meslin Olivier Date: Wed, 31 Jan 2024 13:12:04 +0100 Subject: [PATCH 92/92] =?UTF-8?q?Pr=C3=A9cision=20[skip-ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03_Fiches_thematiques/Fiche_arrow.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_arrow.qmd b/03_Fiches_thematiques/Fiche_arrow.qmd index e97ba5a7..9644bfe4 100644 --- a/03_Fiches_thematiques/Fiche_arrow.qmd +++ b/03_Fiches_thematiques/Fiche_arrow.qmd @@ -439,7 +439,7 @@ Si vous ne savez plus si une table de données est un `Arrow Table` ou un `tibbl ### Surveiller la consommation de RAM de `R` -Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `arrow`. Cela a une conséquence pratique que `R` n'a qu'un contrôle partiel sur la RAM occupé par `arrow`, et parvient pas toujours à libérer la RAM qu'`arrow` a utilisée temporairement pour réaliser un traitement. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Cette imperfection de la gestion de la RAM implique deux choses: +Comme expliqué plus haut, les `Arrow Table` ne sont pas des objets `R` standards, mais des objets C++ qui peuvent être manipulés avec `R` via `arrow`. En pratique, cela signifie que `R` n'a qu'un contrôle partiel sur la RAM occupé par `arrow`, et ne parvient pas toujours à libérer la RAM qu'`arrow` a utilisée temporairement pour réaliser un traitement. En particulier, __la fonction `gc()` ne permet pas de libérer la RAM qu'`arrow` a utilisée temporairement__. Cette imperfection de la gestion de la RAM implique deux choses: - Si on travaille sur des données volumineuses, __il est important de surveiller fréquemment sa consommation de RAM pour s'assurer qu'elle n'est pas excessive__; la fiche [Superviser sa session `R`]{#superviser-ressources}.