Parmi les nombreux formats de fichiers qui émergent afin de permettre le stockage efficace de très gros volumes de données, figure Apache Parquet. Dans ce billet, nous en présentons les principales caractéristiques et précisons en quoi celles-ci font de Parquet un format approprié pour l’analyse dans le cadre d’un projet big data.
Date: 22 mai 2018
Expertises:
Science des données ⊕
Plus que jamais, le big data a le vent en poupe. Au sein de la Région Wallonne, de plus en plus d’entreprises envisagent l’adoption des technologies qu’il recouvre, ou les ont déjà mises en œuvre [1]. Parmi les problématiques traitées par ces technologies figure la quantité importante de données devant être traitée : c’est le premier des « 3 V » et l’une des caractéristiques prédominantes du big data [2]. Le volume de données est aujourd’hui tel que leur stockage et leur accès causent de nouveaux défis techniques, dont la gestion implique la maîtrise de nouveaux outils. Apache Parquet est un format de stockage de données offrant de nombreux avantages lorsque ces défis prennent une ampleur significative dans la réalisation de vos projets.
Une grande variété de formats est disponible afin de stocker les données. Chacun de ces formats a ses propres avantages et inconvénients, de sorte qu’un choix technologique doit s’opérer en fonction des besoins du projet dans cadre duquel il sera mis en œuvre. Quelques principes généraux, parfois contradictoires, semblent toutefois émerger. Leur pertinence devra être évaluée en fonction du contexte.
Pas de limite de taille. Le format de stockage ne doit, en soi, pas être un obstacle à l’enregistrement d’une quantité arbitraire de données. Il est de plus en plus fréquent que le volume de données à considérer se quantifie en Téraoctets, voire en Pétaoctets. Cela rend caduques de nombreuses approches traditionnelles ainsi que les outils qui les mettent en œuvre.
Une bonne compression. Si le coût du stockage de données ne cesse de baisser (au moment de la rédaction du présent billet, ce coût est de l’ordre de 0,04 euro par Go), il reste intéressant de minimiser l’espace nécessaire au stockage d’un jeu de données pour différentes raisons. Dans un contexte de traitement distribué de l’information (ce qui est pratiquement toujours le cas en big data), les données devront être échangées entre les différentes unités de traitement. Ces unités étant connectées entre elles par un réseau informatique aux capacités finies, une représentation plus compacte des données signifie un partage plus rapide de celles-ci, et donc, in fine, de meilleures performances globales. Avant même d’être traitées, les données doivent être lues depuis leur support de stockage. Compresser les données permet de réduire le temps de lecture, et donc le délai préalable au traitement de la donnée.
Une possibilité de passage à l’échelle. Quelle que soit la technologie mise en œuvre, le stockage à moyen et long terme de données numériques repose en fin de compte sur un système de fichiers. Plus ces fichiers sont volumineux, plus il sera difficile pour les unités de traitement de partager, lire, dupliquer, et altérer les informations relatives à une analyse donnée. Inversement, la lecture et la gestion d’un très grand nombre de fichiers de taille réduite posent d’autres problèmes, en particulier de performance. Afin que l’exploitation d’une grande quantité de données soit réalisable un temps raisonnable, il est donc nécessaire que le format de stockage soit basé sur des fichiers d’une taille maîtrisée permettant leur traitement simultané par un nombre arbitraire d’unités de traitement.
De bonnes performances en lecture et en écriture. Le traitement de données consiste essentiellement en l’ajout, la modification et la lecture de l’information qu’elles contiennent. Le format de stockage doit donc permettre la réalisation efficace de ces tâches. Cela amène souvent à l’expression de besoins contradictoires : une approche peut difficilement être efficace aussi bien en lecture qu’en écriture. Dans ce cas, un compromis doit être trouvé en fonction des besoins du projet. Ainsi, le format pourra par exemple être principalement approprié pour l’analyse de données qui n’évoluent plus dans le temps (et donc la lecture) ou bien pour l’ingestion de données fraîchement acquises (et donc l’écriture).
Capacité d’évolution. Il arrive fréquemment qu’une source de données voie la nature ou la structure de l’information qu’elle génère changer au cours du temps. Par exemple, un réseau social peut enrichir les informations relatives à ses utilisateurs. Une usine peut s’équiper d’un ensemble de capteurs de plus en plus complet. Les données doivent donc être gérées de sorte à permettre une évolution du schéma qui les structure.
Apache Parquet est une implémentation des idées présentées par Google dans le cadre du projet Dremel [3]. Il présente plusieurs propriétés qui le distinguent des formats de fichier plus populaires, tels que CSV, et des bases de données traditionnelles.
Présentation des données en colonne
Les données tabulaires (dont chaque ligne représente une entrée, et chaque colonne un attribut des entrées) sont généralement représentées en ligne : lorsqu’on lit les données du début à la fin, on les lit entrée par entrée, et, pour chaque entrée, les attributs sont présentés systématiquement dans le même ordre. C’est par exemple le cas dans la plupart des bases de données relationnelles, dans le format CSV, ou encore lorsqu’un fichier est constitué d’une succession d’objets JSON, chacun de ceux-ci représentant une des entrées.
Avec Parquet, au contraire, les données sont présentées en colonne. Autrement dit, toutes les données du premier attribut sont stockées, puis seulement les données du second attribut, etc.
Cette organisation des données induit plusieurs avantages dans un contexte analytique.
Lire toutes les valeurs d’un attribut (par exemple, pour en calculer une agrégation comme la somme ou le maximum) est plus rapide, car ces valeurs sont placées consécutivement sur un support typiquement conçu pour maximiser l’écriture et la lecture de cellules mémoires consécutives. Lorsque les données sont présentées en ligne, le système doit, pour chaque entrée, repositionner le mécanisme de lecture pour « sauter » tous les attributs qui ne sont pas concernés par la lecture.
La lecture d’un sous-ensemble des attributs est également plus rapide, car toutes les valeurs d’un attribut donné peuvent être ignorées en un seul saut de lecture. Cela réduit drastiquement le nombre d’accès disque à réaliser.
Enfin, les structures de données complexes sont représentées plus efficacement. La représentation des valeurs manquantes (ou nulles) a un coût nettement plus faible qu’avec une représentation en ligne. Par conséquent, il est possible de représenter une structure « complexe », telle qu’une liste ou un dictionnaire, en la « mettant à plat », de sorte à la ramener à une vue tabulaire, même si celle-ci possède de nombreuses données manquantes.
Division en pages et en blocs
Avec Parquet, un jeu de données est divisé en pages. En pratique, chaque page est gérée par le système informatique sous-jacent comme un fichier. Chaque page est elle-même constituée de blocs contenant les colonnes d’un certain nombre d’entrées. Les blocs sont organisés en colonnes comme indiqué précédemment. Une page a généralement une taille comprise entre 100 Mo et 1 Go, de sorte que les fichiers soient aisément manipulables. Cela facilite également le partage des données, la communication d’une page d’une unité de traitement à une autre ne prenant que quelques secondes sur un réseau informatique moderne.
À chaque page (et chaque bloc) sont associées des métadonnées. Il s’agit de statistiques décrivant le contenu de la page (ou du bloc), telles que les valeurs minimales et maximales de chaque colonne. Ces métadonnées sont utilisées afin d’accélérer les recherches réalisées lors d’une analyse. Par exemple, si une recherche ne porte que sur les entrées météorologiques indiquant une température extérieure de 30 °C, et que les métadonnées d’une page indiquent que l’attribut relatif à la température extérieure a des valeurs comprises entre 10 et 24 °C, il est inutile de lire le contenu de la page, car aucune entrée pertinente ne s’y trouve. Il est ainsi possible d’éviter la lecture de nombreuses pages (et blocs), et donc de réduire considérablement le temps total de traitement des données. Une bonne pratique consiste à ordonner les entrées selon les colonnes les plus fréquemment utilisées dans une condition de filtrage. Les entrées ayant des valeurs proches pour ces colonnes seront ainsi placées dans une même page, ce qui augmente le nombre de pages pouvant être exclues lors du filtrage des entrées.
L’organisation des données en pages permet leur traitement simultané par plusieurs unités de traitement. Il suffit en effet que chaque unité se concentre sur un sous-ensemble des pages disponibles.
Encodage
Contrairement aux formats textuels, tels que CSV et JSON, Parquet encode les données en un format binaire. Celui-ci est conçu pour le traitement efficace des données par le CPU [4].
Chaque colonne de chaque page possède un encodage qui lui est propre. L’encodage utilisé dépend de la nature des données de la colonne, ainsi que de leurs valeurs. Si la colonne contient peu de valeurs distinctes (par exemple, lorsqu’elle représente des catégories de produits ou des pays), un dictionnaire est utilisé. Ce dictionnaire est ajouté aux métadonnées de la page et contribue à l’élagage du jeu de données : il suffit en effet de parcourir ce dictionnaire pour déterminer si une valeur d’intérêt figure dans une colonne, plutôt que de lire les valeurs de la colonne proprement dites.
Lorsqu’une colonne contient des valeurs numériques, la variation de ces valeurs peut être encodée plutôt que les valeurs elles-mêmes. Cela permet une représentation très compacte des colonnes dont la valeur varie faiblement d’une entrée à l’autre. C’est le cas notamment des dates (représentées numériquement), de certaines métriques, d’identifiants, etc. Les petites valeurs numériques peuvent être combinées en blocs de 64 octets (bit packing) afin de les représenter plus efficacement.
Les colonnes contenant des chaînes de caractères peuvent également bénéficier d’un encodage différentiel spécifique, qui factorise les préfixes communs pour n’enregistrer que les suffixes variables. Cela est, entre autres, utile pour l’enregistrement de dates (représentées textuellement), d’adresses postales, de messages de statut accompagnés de commentaires, etc.
Enfin, quelle que soit la nature des colonnes, les valeurs répétitives peuvent être représentées par un « run length », c’est-à-dire par la valeur accompagnée du nombre de fois qu’elle se répète.
Dans tous les cas, il peut à nouveau être intéressant d’ordonner les entrées selon certaines colonnes, de sorte que les valeurs proches soient écrites dans la même page et qu’un encodage capable d’en tenir compte puisse être appliqué.
Compression
Facultativement, les données peuvent être compressées par le biais d’un mécanisme tiers. Toutes les pages d’un jeu de données bénéficient du même choix de compression. Il est pour le moment possible d’opter pour les algorithmes gzip [5], brotli [6], ZStandard [7] et Snappy [8]. Par défaut, Snappy est utilisé. S’il n’est pas particulièrement performant en termes de taux de compression (gzip est presque systématiquement meilleur sur ce point), Snappy est optimisé pour la vitesse d’exécution, en particulier lors d’une décompression des données. Cela est approprié dans un contexte d’analyse de données big data, où le volume de données est de toute façon conséquent, mais où le temps de traitement en lecture est primordial.
La compression est facilitée par le fait que les données sont présentées en colonne. Par définition, cela implique que les pages contiennent des séquences de valeurs de même nature, qui sont encodées de la même manière. Cette uniformité des données permet une compression potentiellement plus efficace.
Autres propriétés
Contrairement à de nombreux autres systèmes de stockage, Parquet ne propose pas de mécanisme d’indexation. Un tel mécanisme est peu utile dans un contexte d’analyse de données big data, où il est rare qu’on s’intéresse à une entrée particulière. De plus, dans ce contexte, les jointures entre différentes tables de données sont généralement à proscrire, du fait de leur coût prohibitif. À nouveau, cela réduit l’intérêt d’une indexation du contenu stocké.
Afin d’accélérer davantage le filtrage des données, les pages Parquet sont souvent organisées de manière hiérarchique, selon le principe des partitions de Hive [9]. Par exemple, si le jeu de données porte sur des enregistrements d’un réseau de capteurs au sein d’une usine, et qu’on charge les données provenant de l’implantation belge datant du 7 juin 2018, on ne s’intéressera qu’aux pages situées dans le répertoire /plant=BE/year=2018/month=06/day=07/.
Conclusion
Apache Parquet est un format de fichier conçu pour stocker de très gros volumes de données ayant une structure « complexe ». Alors qu’il est particulièrement efficace pour l’analyse de données (lecture de fichiers et filtrage des entrées), il ne convient pas à l’ajout de données « en continu » ou à la modification fréquente de données existantes.
L’organisation simple, mais efficace des données en fichiers facilite la distribution de la charge de traitement, tandis que leur structuration permet d’exclure rapidement des pans entiers du jeu de données, et donc de réduire d’autant le temps de traitement.
Ces propriétés font de Parquet un format approprié pour la réalisation d’analyses à grande échelle. Cependant, afin de tirer pleinement profit des fonctionnalités qu’il propose, il sera nécessaire de définir les colonnes qui seront le plus souvent impliquées dans une opération de filtrage. Les performances observées lors de l’exploitation d’un jeu de données Parquet dépendront donc, entre autres, du contexte de l’analyse réalisée.
[2] A. De Mauro et al. (2016). "A Formal definition of Big Data based on its essential Features". Library Review. 65 : 122–135. doi:10.1108/LR-06-2015-0061
[4] D. Lemire and L. Boytsov. Decoding billions of integers per second through vectorization. Softw. Pract. Exper., 45(1):1–29, Jan. 2015.