Passer au contenu principal
Les fichiers Tab Separated Value, ou TSV, sont courants et peuvent inclure des en-têtes de colonnes sur la première ligne du fichier. ClickHouse peut ingérer des fichiers TSV, et peut aussi interroger des fichiers TSV sans les ingérer. Ce guide couvre ces deux cas. Si vous devez interroger ou ingérer des fichiers CSV, les mêmes techniques s’appliquent ; remplacez simplement TSV par CSV dans vos arguments de format. En suivant ce guide, vous allez :
  • Examiner : interroger la structure et le contenu du fichier TSV.
  • Déterminer le schéma ClickHouse cible : choisir les types de données appropriés et faire correspondre les données existantes à ces types.
  • Créer une table ClickHouse.
  • Prétraiter et transmettre en flux les données vers ClickHouse.
  • Exécuter quelques requêtes dans ClickHouse.
Le jeu de données utilisé dans ce guide provient de l’équipe NYC Open Data et contient des données sur « tous les crimes, délits et contraventions valides signalés au New York City Police Department (NYPD) ». Au moment de la rédaction, le fichier de données pèse 166 Mo, mais il est mis à jour régulièrement. Source : data.cityofnewyork.us Conditions d’utilisation : https://www1.nyc.gov/home/terms-of-use.page

Prérequis

Remarque sur les commandes décrites dans ce guide

Ce guide contient deux types de commandes :
  • Certaines commandes servent à interroger les fichiers TSV ; elles s’exécutent dans le terminal.
  • Les autres servent à interroger ClickHouse et s’exécutent dans clickhouse-client ou dans l’UI Play.
Les exemples de ce guide supposent que vous avez enregistré le fichier TSV sous ${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv ; adaptez les commandes si nécessaire.

Familiarisez-vous avec le fichier TSV

Avant de commencer à travailler avec la base de données ClickHouse, prenez connaissance des données.

Examinez les champs du fichier TSV source

Voici un exemple de commande pour interroger un fichier TSV, mais ne l’exécutez pas encore.
Query
Exemple de réponse
La plupart du temps, la commande ci-dessus vous indiquera quels champs des données d’entrée sont numériques, lesquels sont des chaînes de caractères et lesquels sont des tuples. Ce n’est toutefois pas toujours le cas. Comme ClickHouse est couramment utilisé avec des jeux de données contenant des milliards d’enregistrements, un nombre de lignes à examiner par défaut (100) est défini pour inférer le schéma, afin d’éviter d’analyser des milliards de lignes pour l’inférer. La réponse ci-dessous peut ne pas correspondre à ce que vous voyez, car le jeu de données est mis à jour plusieurs fois par an. En consultant le dictionnaire de données, vous pouvez voir que CMPLNT_NUM est défini comme du texte, et non comme une valeur numérique. En remplaçant la valeur par défaut de 100 lignes pour l’inférence par le paramètre SETTINGS input_format_max_rows_to_read_for_schema_inference=2000 vous obtiendrez une meilleure idée du contenu.Remarque : à partir de la version 22.5, la valeur par défaut est désormais de 25 000 lignes pour l’inférence du schéma. Ne modifiez donc ce paramètre que si vous utilisez une version antérieure ou si vous avez besoin d’échantillonner plus de 25 000 lignes.
Exécutez cette commande dans votre terminal. Vous utiliserez clickhouse-local pour interroger les données du fichier TSV que vous avez téléchargé.
Query
Response
À ce stade, vous devez vérifier que les colonnes du fichier TSV correspondent aux noms et aux types indiqués dans la section Colonnes de ce jeu de données de la page du jeu de données. Les types de données ne sont pas très précis : tous les champs numériques sont en Nullable(Float64) et tous les autres champs en Nullable(String). Lorsque vous créez une table ClickHouse pour stocker les données, vous pouvez définir des types plus appropriés et plus performants.

Déterminer le schéma approprié

Pour déterminer quels types doivent être utilisés pour les champs, il faut savoir à quoi ressemblent les données. Par exemple, le champ JURISDICTION_CODE est numérique : doit-il être de type UInt8 ou Enum, ou bien Float64 convient-il ?
Query
Response
La réponse à la requête montre que JURISDICTION_CODE tient bien dans un UInt8. De même, examinez certains champs String et voyez s’ils conviendraient mieux comme champs DateTime ou LowCardinality(String). Par exemple, le champ PARKS_NM est décrit comme “Nom du parc, de l’aire de jeux ou de l’espace vert de NYC où l’événement s’est produit, le cas échéant (les parcs d’État ne sont pas inclus)”. Les noms des parcs de New York peuvent être de bons candidats pour un LowCardinality(String) :
Query
Response
Examinez quelques noms de parcs :
Query
Response
Le jeu de données utilisé au moment de la rédaction ne comporte que quelques centaines de parcs et d’aires de jeux distincts dans la colonne PARK_NM. Ce nombre reste faible au regard de la recommandation LowCardinality, qui préconise de rester en dessous de 10 000 chaînes distinctes dans un champ LowCardinality(String).

Champs DateTime

D’après la section Columns in this Dataset de la page web du jeu de données, il existe des champs de date et d’heure pour le début et la fin de l’événement signalé. L’examen des valeurs minimale et maximale de CMPLNT_FR_DT et CMPLT_TO_DT permet de déterminer si ces champs sont toujours renseignés ou non :
Query
Response
Query
Response
Query
Response
Query
Response

Établir un plan

D’après l’analyse ci-dessus :
  • JURISDICTION_CODE doit être converti en UInt8.
  • PARKS_NM doit être converti en LowCardinality(String)
  • CMPLNT_FR_DT et CMPLNT_FR_TM sont toujours renseignés (éventuellement avec une heure par défaut de 00:00:00)
  • CMPLNT_TO_DT et CMPLNT_TO_TM peuvent être vides
  • Dans les données source, les dates et les heures sont stockées dans des champs distincts
  • Les dates sont au format mm/dd/yyyy
  • Les heures sont au format hh:mm:ss
  • Les dates et les heures peuvent être concaténées en types DateTime
  • Certaines dates sont antérieures au 1er janvier 1970, ce qui signifie qu’il nous faut un DateTime sur 64 bits
Il reste de nombreuses autres modifications à apporter aux types, et elles peuvent toutes être déterminées en suivant les mêmes étapes d’analyse. Examinez le nombre de chaînes distinctes dans un champ, les valeurs minimales et maximales des données numériques, puis prenez vos décisions. Le schéma de table présenté plus loin dans le guide contient de nombreuses chaînes à faible cardinalité et des champs d’entiers non signés, et très peu de nombres à virgule flottante.

Concaténer les champs de date et d’heure

Pour concaténer les champs de date et d’heure CMPLNT_FR_DT et CMPLNT_FR_TM en une seule String pouvant être convertie en DateTime, sélectionnez les deux champs reliés par l’opérateur de concaténation : CMPLNT_FR_DT || ' ' || CMPLNT_FR_TM. Les champs CMPLNT_TO_DT et CMPLNT_TO_TM sont traités de la même manière.
Query
Response

Convertir la chaîne de date et d’heure en type DateTime64

Plus tôt dans ce guide, nous avons constaté que le fichier TSV contient des dates antérieures au 1er janvier 1970, ce qui signifie que nous devons utiliser un type DateTime64 pour ces dates. Les dates doivent également être converties du format MM/DD/YYYY au format YYYY/MM/DD. Ces deux opérations peuvent être effectuées avec parseDateTime64BestEffort().
Query
Les lignes 2 et 3 ci-dessus contiennent la concaténation de l’étape précédente, et les lignes 4 et 5 ci-dessus convertissent les chaînes en DateTime64. Comme l’heure de fin de la réclamation n’est pas garantie, parseDateTime64BestEffortOrNull est utilisé.
Response
Les dates affichées ci-dessus comme 1925 proviennent d’erreurs dans les données. Plusieurs enregistrements des données d’origine comportent des dates des années 1019 à 1022, alors qu’il devrait s’agir de 2019 à 2022. Elles sont stockées sous la forme du 1er janvier 1925, car il s’agit de la date la plus ancienne prise en charge par un DateTime 64 bits.

Créer une table

Les décisions prises ci-dessus concernant les types de données utilisés pour les colonnes se reflètent dans le schéma de la table ci-dessous. Nous devons également définir les clauses ORDER BY et PRIMARY KEY à utiliser pour la table. Au moins une des clauses ORDER BY ou PRIMARY KEY doit être spécifiée. Voici quelques recommandations pour choisir les colonnes à inclure dans ORDER BY. Vous trouverez plus d’informations dans la section Étapes suivantes à la fin de ce document.

clauses ORDER BY et PRIMARY KEY

  • Le tuple ORDER BY doit inclure les champs utilisés dans les filtres de requête
  • Pour maximiser la compression sur disque, le tuple ORDER BY doit être ordonné par cardinalité croissante
  • S’il existe, le tuple PRIMARY KEY doit être un sous-ensemble du tuple ORDER BY
  • Si seul ORDER BY est spécifié, le même tuple sera alors utilisé comme PRIMARY KEY
  • L’index de clé primaire est créé à l’aide du tuple PRIMARY KEY s’il est spécifié, sinon du tuple ORDER BY
  • L’index PRIMARY KEY est conservé en mémoire principale
En examinant le jeu de données et les questions auxquelles son interrogation pourrait répondre, nous pourrions décider de nous intéresser aux types de crimes signalés au fil du temps dans les cinq boroughs de New York City. Ces champs pourraient alors être inclus dans ORDER BY : Interrogation du fichier TSV pour obtenir la cardinalité des trois colonnes candidates :
Query
Response
En triant par cardinalité, le ORDER BY devient :
Le tableau ci-dessous utilisera des noms de colonnes plus lisibles ; les noms ci-dessus seront associés à
En combinant les modifications apportées aux types de données et au tuple ORDER BY, on obtient cette structure de table :

Trouver la clé primaire d’une table

La base de données ClickHouse system, plus précisément system.table, contient toutes les informations sur la table que vous venez de créer. Cette requête affiche l’ORDER BY (clé de tri) et la PRIMARY KEY :
Réponse

Prétraiter et importer des données

Nous utiliserons l’outil clickhouse-local pour prétraiter les données et clickhouse-client pour les importer.

Arguments utilisés par clickhouse-local

table='input' figure parmi les arguments de clickhouse-local ci-dessous. clickhouse-local prend les données fournies en entrée (cat ${HOME}/NYPD_Complaint_Data_Current__Year_To_Date_.tsv) et les insère dans une table. Par défaut, cette table s’appelle table. Dans ce guide, le nom de la table est défini sur input afin de rendre le flux de données plus clair. Le dernier argument de clickhouse-local est une requête qui lit les données de la table (FROM input), puis les transmet à clickhouse-client pour alimenter la table NYPD_Complaint.

Vérifiez les données

Le jeu de données est mis à jour une ou plusieurs fois par an ; vos décomptes peuvent donc ne pas correspondre à ceux indiqués dans ce document.
Query
Response
La taille du jeu de données dans ClickHouse ne représente que 12 % de celle du fichier TSV d’origine ; comparez la taille du fichier TSV d’origine à celle de la table :
Query
Response

Exécutez quelques requêtes

Requête 1. Comparer le nombre de plaintes par mois

Query
Response

Requête 2. Comparer le nombre total de plaintes par borough

Query
Response

Étapes suivantes

Une introduction pratique aux index primaires clairsemés dans ClickHouse présente les différences entre l’indexation dans ClickHouse et celle des bases de données relationnelles traditionnelles, explique comment ClickHouse construit et utilise un index primaire clairsemé, et décrit les bonnes pratiques en matière d’indexation.
Dernière modification le 3 juillet 2026