# Charger des données TsFile

[TsFile](https://tsfile.apache.org/) est un format de fichier en colonnes conçu pour les données de séries temporelles et utilisé comme couche de stockage native d'[Apache IoTDB](https://iotdb.apache.org/). Par rapport aux formats en colonnes généralistes tels que Parquet, TsFile prend en compte le modèle de données de séries temporelles (horodatages, appareils et mesures) et maintient un index temporel interne qui permet l'élagage par plage de temps sans balayage des fichiers entiers.

Ce chargeur est présenté dans un guide distinct car il ne suit pas la convention tabulaire habituelle d’une ligne par enregistrement : chaque ligne de sortie correspond à un *device*, et les valeurs par mesure sont renvoyées sous forme de colonnes Arrow `list<...>`. Le mapping est décrit en détail ci-dessous.

## Installation

Le chargeur dépend du paquet Python [`tsfile`](https://pypi.org/project/tsfile/) :

```bash
pip install "tsfile>=2.3.0"
```

## Modèle de données et disposition de la sortie

Le chargeur suit le *modèle de table* de TsFile. Chaque colonne de table est l'une des suivantes :

- **TAG** — un identifiant de type chaîne de caractères ; le tuple des valeurs de TAG identifie de manière unique un *device* (c’est-à-dire une source de séries temporelles unique).
- **FIELD** — une mesure dont la valeur évolue dans le temps.
- **TIME** — la colonne horodatée, nommée `time` par défaut.

Le chargeur émet une ligne de jeu de données par appareil. Au sein d'une ligne, la colonne `time` et chaque colonne FIELD sont des colonnes Arrow `list<...>` contenant la série temporelle complète de l'appareil, triée par ordre chronologique croissant. Les colonnes TAG apparaissent comme des colonnes scalaires `string`.

Concrètement, le schéma de sortie a la forme suivante :

```text
<tag_1>:    string
<tag_2>:    string                       # one column per TAG
...
time:       list<timestamp[unit, tz]>
<field_1>:  list<original_type>          # one column per FIELD
<field_2>:  list<original_type>
...
```

Lorsqu'un même appareil apparaît dans plusieurs fichiers d'entrée d'une partition, ses segments par fichier sont concaténés et triés par horodatage avant d'être émis en tant que ligne unique. Les horodatages en double pour le même appareil déclenchent une `ValueError`.

## Utilisation de base

Charger un fichier TsFile unique :

```py
>>> from datasets import load_dataset
>>> dataset = load_dataset("tsfile", data_files="my_data.tsfile")
```

Associer explicitement les fichiers à des splits :

```py
>>> dataset = load_dataset(
...     "tsfile",
...     data_files={"train": "train_data.tsfile", "test": "test_data.tsfile"},
... )
```

## Exemple de jeu de données sur le Hub

Un exemple prêt à l’emploi est disponible dans [`tsfile/lotsa_data`](https://huggingface.co/datasets/tsfile/lotsa_data). Comme les fichiers `.tsfile` sont reconnus automatiquement, vous pouvez le charger par identifiant de dépôt sans spécifier `data_files` :

```py
>>> from datasets import load_dataset
>>> dataset = load_dataset("tsfile/lotsa_data")
>>> dataset
DatasetDict({
    train: Dataset({
        features: ['timeseries_id', 'time', 'value'],
        num_rows: 91
    })
})
```

Chaque ligne correspond à un appareil. La colonne TAG `timeseries_id` identifie l’appareil, tandis que `time` et `value` sont des colonnes `list<...>` contenant la série complète de cet appareil :

```py
>>> row = dataset["train"][0]
>>> row["timeseries_id"]
'Bear_assembly_Angel'
>>> len(row["time"]), len(row["value"])
(8760, 8760)
>>> row["time"][:3]
[datetime.datetime(2017, 1, 1, 0, 0), datetime.datetime(2017, 1, 1, 1, 0), datetime.datetime(2017, 1, 1, 2, 0)]
```

## Sélectionner un tableau

Un fichier TsFile peut contenir plusieurs tables. Lorsque `table_name` est omis, la première table trouvée dans le premier fichier valide est utilisée. Les recherches sont insensibles à la casse.

```py
>>> dataset = load_dataset("tsfile", data_files="my_data.tsfile", table_name="sensor_data")
```

## Sélection de colonnes

`columns` restreint les colonnes FIELD qui sont lues. Les colonnes TAG et la colonne `time` sont toujours renvoyées car elles identifient l’appareil et sa chronologie. Les noms dans `columns` qui font référence à un TAG ou à la colonne `time` sont ignorés silencieusement (ils sont émis comme d’habitude, une seule fois) ; les noms qui correspondent à un champ absent de tous les fichiers deviennent des colonnes de listes entièrement nulles.

```py
>>> dataset = load_dataset(
...     "tsfile",
...     data_files="my_data.tsfile",
...     columns=["temperature", "humidity"],
... )
```

## Filtrage par plage de temps

`start_time` et `end_time` sont des bornes inclusives ; l’une ou l’autre peut être omise. Les bornes sont propagées jusqu’à l’index temporel interne de TsFile, de sorte que seuls les blocs de données correspondants sont lus depuis le disque. Les deux bornes acceptent l’un des éléments suivants :

- `int` — époque brute en `timestamp_unit` (millisecondes par défaut) ;
- `datetime.datetime` — les valeurs naïves sont interprétées comme étant en UTC, les valeurs avec fuseau horaire sont converties en UTC ;
- `datetime.date`;
- ISO-8601 `str`, par exemple `"2024-01-01T00:00:00"` ;
- `pyarrow.TimestampScalar`.

```py
>>> from datetime import datetime
>>> dataset = load_dataset(
...     "tsfile",
...     data_files="my_data.tsfile",
...     start_time=datetime(2023, 11, 14),
...     end_time="2023-11-15T00:00:00",
... )
```

## Évolution du schéma entre les fichiers

Lorsque différents fichiers exposent des colonnes différentes — par exemple, si un nouveau champ de capteur est introduit plus tard — le chargeur prend l'union de toutes les colonnes FIELD et remplit les valeurs manquantes par des nulls. Les types numériques FIELD sont promus selon les règles d'élargissement d'IoTDB (`INT32 → INT64 → DOUBLE`, `INT32 → FLOAT → DOUBLE`).

```py
>>> dataset = load_dataset("tsfile", data_files=["day1.tsfile", "day2.tsfile"])
```

## Gestion des fichiers illisibles

Par défaut, une entrée illisible ou non-TsFile provoque une erreur. Définissez `on_bad_files` sur `"warn"` pour journaliser et continuer, ou sur `"skip"` pour ignorer silencieusement le fichier.

```py
>>> dataset = load_dataset("tsfile", data_files="data/*.tsfile", on_bad_files="skip")
```

## Unité de timestamp et fuseau horaire

`timestamp_unit` (par défaut `"ms"`, conformément à IoTDB) contrôle la résolution de la colonne `time` et l’interprétation des bornes temporelles entières. `timestamp_tz` associe un fuseau horaire au type de timestamp Arrow ; `None` (la valeur par défaut) produit un type sans fuseau horaire.

```py
>>> dataset = load_dataset(
...     "tsfile",
...     data_files="my_data.tsfile",
...     timestamp_unit="us",
...     timestamp_tz="UTC",
... )
```

## Mémoire et lot

Deux paramètres contrôlent l'utilisation de la mémoire :

- `input_batch_size` (par défaut `65_536`) — nombre maximal de lignes récupérées par lot Arrow depuis `TsFileReader.query_table`. Limite la mémoire maximale utilisée lors du streaming sur un seul appareil.
- `output_batch_size` (valeur par défaut `32`) — nombre d’appareils regroupés dans chaque lot de records Arrow transmis à l’écriture. Des valeurs plus faibles offrent un suivi de progression plus réactif ; des valeurs plus élevées réduisent le surcoût par lot.

```py
>>> dataset = load_dataset(
...     "tsfile",
...     data_files="large_data.tsfile",
...     input_batch_size=32_768,
...     output_batch_size=128,
... )
```

La mémoire maximale est limitée par la charge utile d'un seul appareil sur l'ensemble de la partition, et non par la taille de la partition dans son ensemble.

Voir [TsFileConfig](/docs/datasets/main/fr/package_reference/loading_methods#datasets.packaged_modules.tsfile.TsFileConfig) pour la liste complète des paramètres.

