Passer au contenu principal
ClickHouse peut déterminer automatiquement la structure de données JSON. Cela permet d’interroger directement des données JSON, par exemple sur disque avec clickhouse-local ou dans des buckets S3, et/ou de créer automatiquement des schémas avant de charger les données dans ClickHouse.

Quand utiliser l’inférence de type

  • Structure cohérente - Les données à partir desquelles les types seront inférés contiennent toutes les clés qui vous intéressent. L’inférence de type repose sur l’échantillonnage des données jusqu’à un nombre maximal de lignes ou d’octets. Les données situées après l’échantillon, avec des colonnes supplémentaires, seront ignorées et ne pourront pas être interrogées.
  • Types cohérents - Les types de données associés à certaines clés doivent être compatibles, c’est-à-dire qu’il doit être possible de convertir automatiquement un type en un autre.
Si votre JSON est plus dynamique, avec de nouvelles clés ajoutées et plusieurs types possibles pour le même chemin, consultez “Working with semi-structured and dynamic data”.

Détection des types

La suite suppose que le JSON a une structure cohérente et qu’un seul type est associé à chaque chemin. Dans nos exemples précédents, nous avons utilisé une version simplifiée du Python PyPI dataset au format NDJSON. Dans cette section, nous examinons un jeu de données plus complexe avec des structures imbriquées : le jeu de données arXiv, qui contient 2,5 millions d’articles scientifiques. Chaque ligne de ce jeu de données, fourni au format NDJSON, représente un article scientifique publié. Un exemple de ligne est présenté ci-dessous :
Ces données nécessitent un schéma bien plus complexe que dans les exemples précédents. Nous décrivons ci-dessous le processus de définition de ce schéma, en introduisant des types complexes tels que Tuple et Array. Ce jeu de données est stocké dans un bucket S3 public à l’emplacement s3://datasets-documentation/arxiv/arxiv.json.gz. Vous pouvez constater que le jeu de données ci-dessus contient des objets JSON imbriqués. Même si vous devez rédiger et versionner vos schémas, l’inférence permet de déduire les types à partir des données. Cela permet de générer automatiquement le DDL du schéma, ce qui évite d’avoir à le construire manuellement et accélère le processus de développement.
Détection automatique du formatEn plus de détecter le schéma, l’inférence de schéma JSON détermine automatiquement le format des données à partir de l’extension du fichier et de son contenu. Le fichier ci-dessus est ainsi automatiquement identifié comme étant au format NDJSON.
L’utilisation de la fonction s3 avec la commande DESCRIBE affiche les types qui seront déduits.
Évitez les valeurs NULLVous pouvez constater que de nombreuses colonnes sont détectées comme Nullable. Nous déconseillons d’utiliser le type Nullable sauf en cas de nécessité absolue. Vous pouvez utiliser schema_inference_make_columns_nullable pour contrôler les cas où Nullable est appliqué.
Nous pouvons constater que la plupart des colonnes ont été automatiquement détectées comme String, et que la colonne update_date a bien été détectée comme Date. La colonne versions a été créée comme Array(Tuple(created String, version String)) pour stocker une liste d’objets, tandis que authors_parsed est défini comme Array(Array(String)) pour les tableaux imbriqués.
Contrôle de la détection des typesLa détection automatique des dates et des valeurs DateTime peut être contrôlée respectivement à l’aide des paramètres input_format_try_infer_dates et input_format_try_infer_datetimes (tous deux activés par défaut). L’inférence d’objets sous forme de tuples est contrôlée par le paramètre input_format_json_try_infer_named_tuples_from_objects. D’autres paramètres qui contrôlent l’inférence de schéma pour le JSON, comme la détection automatique des nombres, sont disponibles ici.

Interroger des données JSON

La suite suppose que le JSON présente une structure cohérente et un seul type pour chaque chemin. Nous pouvons nous appuyer sur l’inférence de schéma pour interroger directement les données JSON. Ci-dessous, nous identifions les principaux auteurs pour chaque année, en tirant parti du fait que les dates et les tableaux sont détectés automatiquement.
L’inférence de schéma permet d’interroger des fichiers JSON sans avoir à spécifier le schéma, ce qui accélère les tâches d’analyse de données ad hoc.

Création de tables

Nous pouvons nous appuyer sur l’inférence de schéma pour définir le schéma d’une table. La commande CREATE AS EMPTY suivante permet d’inférer le DDL de la table et de créer celle-ci. Cela ne charge aucune donnée :
Pour vérifier le schéma de la table, nous utilisons la commande SHOW CREATE TABLE :
Ce qui précède est le schéma correct pour ces données. L’inférence de schéma repose sur l’échantillonnage des données et sur leur lecture ligne par ligne. Les valeurs des colonnes sont extraites selon le format, à l’aide de parseurs récursifs et d’heuristiques permettant de déterminer le type de chaque valeur. Le nombre maximal de lignes et d’octets lus à partir des données lors de l’inférence de schéma est contrôlé par les paramètres input_format_max_rows_to_read_for_schema_inference (25000 par défaut) et input_format_max_bytes_to_read_for_schema_inference (32MB par défaut). Si la détection est incorrecte, vous pouvez fournir des indications comme décrit ici.

Création de tables à partir d’extraits

L’exemple ci-dessus utilise un fichier sur S3 pour créer le schéma de table. Vous souhaiterez peut-être créer un schéma à partir d’un extrait d’une seule ligne. Pour ce faire, utilisez la fonction format, comme indiqué ci-dessous :

Chargement de données JSON

La suite suppose que le JSON a une structure cohérente et qu’il n’existe qu’un seul type pour chaque chemin. Les commandes précédentes ont créé une table dans laquelle les données peuvent être chargées. Vous pouvez maintenant insérer les données dans votre table à l’aide de l’instruction INSERT INTO SELECT suivante :
Pour des exemples de chargement de données à partir d’autres sources, par exemple un fichier, consultez ici. Une fois les données chargées, nous pouvons les interroger, en utilisant si besoin le format PrettyJSONEachRow pour afficher les lignes dans leur structure d’origine :

Gestion des erreurs

Il peut arriver que certaines données soient incorrectes. Par exemple, certaines colonnes peuvent ne pas avoir le bon type, ou un objet JSON peut être mal formaté. Dans ce cas, vous pouvez utiliser les paramètres input_format_allow_errors_num et input_format_allow_errors_ratio pour autoriser l’ignorance d’un certain nombre de lignes si les données provoquent des erreurs d’insertion. De plus, des indications peuvent être fournies pour faciliter l’inférence.

Travailler avec des données semi-structurées et dynamiques

Dans notre exemple précédent, nous utilisions un JSON statique, avec des noms de clés et des types bien définis. Ce n’est toutefois pas toujours le cas : des clés peuvent être ajoutées ou leur type peut changer. C’est courant dans des cas d’usage comme les données d’observabilité. ClickHouse gère ce cas grâce à un type JSON dédié. Si vous savez que votre JSON est très dynamique, avec un grand nombre de clés uniques et plusieurs types possibles pour une même clé, nous vous recommandons de ne pas utiliser l’inférence de schéma avec JSONEachRow pour essayer d’inférer une colonne pour chaque clé, même si les données sont au format JSON délimité par des retours à la ligne. Prenons l’exemple suivant, issu d’une version enrichie du jeu de données Python PyPI dataset présenté plus haut. Nous y avons ajouté une colonne tags arbitraire contenant des paires clé-valeur aléatoires.
Un échantillon de ces données est accessible publiquement au format JSON délimité par des sauts de ligne. Si nous tentons une inférence de schéma sur ce fichier, vous constaterez que les performances sont médiocres et que la réponse est extrêmement détaillée :
Le principal problème ici est que le format JSONEachRow est utilisé pour l’inférence. Il tente d’inférer un type de colonne pour chaque clé du JSON — autrement dit, d’appliquer un schéma statique aux données sans utiliser le type JSON. Avec des milliers de colonnes uniques, cette approche de l’inférence est lente. À la place, vous pouvez utiliser le format JSONAsObject. JSONAsObject traite l’entrée entière comme un seul objet JSON et la stocke dans une seule colonne de type JSON, ce qui le rend plus adapté aux payloads JSON très dynamiques ou imbriqués.
Ce format est également essentiel lorsque des colonnes ont plusieurs types qui ne peuvent pas être conciliés. Par exemple, considérons un fichier sample.json contenant le JSON délimité par des retours à la ligne suivant :
Dans ce cas, ClickHouse peut résoudre le conflit de types par coercition et traiter la colonne a comme un Nullable(String).
Conversion de typeCette conversion de type peut être contrôlée à l’aide d’un certain nombre de paramètres. L’exemple ci-dessus dépend du paramètre input_format_json_read_numbers_as_strings.
Cependant, certains types sont incompatibles. Prenons l’exemple suivant :
Dans ce cas, aucune conversion de type n’est possible. La commande DESCRIBE échoue donc :
Dans ce cas, JSONAsObject considère chaque ligne comme une unique valeur de type JSON (ce qui permet à une même colonne d’avoir plusieurs types). C’est essentiel :

Pour aller plus loin

Pour en savoir plus sur l’inférence des types de données, vous pouvez consulter cette page de documentation.
Dernière modification le 29 juin 2026