From d5f780907fea4eeb72d26bd886f6f4ea2fcb95bf Mon Sep 17 00:00:00 2001 From: nbc Date: Fri, 26 Apr 2024 16:58:19 +0200 Subject: [PATCH] proposition d'ajout sur les fichiers parquet (#523) * proposition d'ajout sur les fichiers parquet * Update 03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd * Update 03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd --------- Co-authored-by: Lino Galiana --- .../Fiche_import_fichiers_parquet.qmd | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd index d41776b1..242d8b58 100644 --- a/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd +++ b/03_Fiches_thematiques/Fiche_import_fichiers_parquet.qmd @@ -48,7 +48,8 @@ Le format Parquet présente trois caractéristiques importantes du point de l'ut knitr::include_graphics("../pics/parquet/stockage_colonne.png") ``` -- **Un fichier Parquet contient à la fois les données et des métadonnées**. Ces métadonnées écrites à la fin du fichier enregistrent une description du fichier (appelé **schéma**). Ces métadonnées contiennent notamment le type de chaque colonne (entier/réel/caractère). Ce sont ces métadonnées qui font en sorte que la lecture des données Parquet soit optimisée et sans risque d’altération (voir [ici](https://parquet.apache.org/docs/file-format/metadata/) pour en savoir plus). +- **Un fichier Parquet contient à la fois les données et des métadonnées**. Ces métadonnées écrites à la fin du fichier enregistrent une description du fichier (appelé **schéma**). Ces métadonnées contiennent notamment le type de chaque colonne (entier/réel/caractère) et quelques statistiques (min, max). Ce sont ces métadonnées qui font en sorte que la lecture des données Parquet soit optimisée et sans risque d’altération (voir [ici](https://parquet.apache.org/docs/file-format/metadata/) pour en savoir plus). +- **Un fichier Parquet est composé de groupe de lignes (row group)** contenant également des métadonnées similaires à celles du fichier. La taille idéale d'un row group est de l'ordre de 30 000 à 1 000 000. Dans un contexte analytique, cette organisation des données génère plusieurs avantages dont les principaux sont: @@ -131,6 +132,7 @@ Partitionner un fichier revient à le "découper" selon une clé de partitionnem - **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 d'une ou deux variables de partitionnement. +- **Si vous souhaitez être compatible avec tous les outils lisant du parquet**, il est recommandé de ne pas partitionner sur une variable pouvant être `NA` ou une chaîne vide. ::: 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 : @@ -150,6 +152,50 @@ Avec cette instruction, on a créé autant de répertoires que de modalités dif knitr::include_graphics("../pics/parquet/fichier_partition.png") ``` +### Données volumineuses: optimiser en triant + +Il n'est pas toujours possible ou souhaitable de partitionner un fichier si la variable de partitionnement possède de trop nombreuses modalités (si celle-ci est non discrète ou possède des milliers de modalités...). Dans ces cas là, vous pouvez trier le fichier par la variable à utiliser, cela va permettre une recherche efficace à partir des métadonnées des fichiers et des groupes de lignes. + +```{r, eval = FALSE} +donnees_BPE |> + arrange(EPCI) |> + write_parquet( + sink = "Data_parquet/BPE_ENS.parquet" + ) +``` + +Vous pouvez bien sûr cumuler les partitions avec des tris : + +```{r, eval = FALSE} +donnees_BPE |> + arrange(EPCI) |> + write_dataset( + path = "Data/", + partitioning = c("REG"), # la variable de partitionnement + format="parquet" + ) +``` + +Cette méthode est quasiment aussi efficace que le partitionnement. + +### Vérifier qu'un fichier parquet est correctement optimisé + +Dans certains cas pathologiques quand vous manipulez de très gros volumes de données (par exemple quand vous partitionnez avec `arrow::open_dataset` un volume de données de plusieurs de dizaine de millions de lignes), le package `arrow` peut générer des fichiers parquet avec un nombre de lignes par row group très petite (inférieur à 1000 voire à 100). Cela rendra toutes les requêtes sur vos fichiers extrèmement lent. + +Pour vérifier que vos fichiers ont une taille de row group correcte, vous pouvez utiliser la fonction suivante : + +```{r, eval = FALSE} +library(arrow) + +mean_row_group_size <- function(path) { + a <- arrow::ParquetFileReader$create(path) + (a$num_rows / a$num_row_groups) +} +mean_row_group_size('bpe2018/REG=11/part-0.parquet') +``` + +Vous devez obtenir une valeur au moins égale à 10 000. Si vous obtenez une valeur inférieure, vous aurez intérêt à regénérer votre fichier en passant par d'autres méthodes (par exemple générer chaque partition en faisant une boucle et un filtre). + ## Lire et exploiter un fichier Parquet avec `R` {#readparquet} ### Cas des données peu volumineuses: importer les données en mémoire