> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentation du type de données QBit dans ClickHouse, qui permet une quantification fine pour la recherche vectorielle approximative

# Type de données QBit

Le type de données `QBit` réorganise le stockage des vecteurs pour accélérer les recherches approximatives. Au lieu de stocker ensemble les éléments de chaque vecteur, il regroupe les mêmes positions de bits binaires pour l’ensemble des vecteurs.
Ce type stocke les vecteurs à pleine précision tout en vous permettant de choisir le niveau de quantification fine au moment de la recherche : lisez moins de bits pour réduire les E/S et accélérer les calculs, ou davantage de bits pour une précision accrue. Vous bénéficiez ainsi des gains de vitesse liés à la réduction des transferts de données et des calculs grâce à la quantification, tout en conservant l’accès aux données d’origine lorsque nécessaire.

Pour déclarer une colonne de type `QBit`, utilisez la syntaxe suivante :

```sql theme={null}
column_name QBit(element_type, dimension[, stride])
```

* `element_type` – le type de chaque élément du vecteur. Les types autorisés sont `Int8`, `BFloat16`, `Float32` et `Float64`
* `dimension` – le nombre d’éléments de chaque vecteur
* `stride` – facultatif. Le nombre de dimensions stockées ensemble dans un groupe de flux. S’il est omis, la valeur par défaut est `dimension` (un seul groupe). Lorsqu’il est spécifié, `dimension` doit être un multiple de `stride` et, lorsque `stride` est inférieur à `dimension`, `stride` doit être un multiple de 8. Les `dimension` dimensions sont réparties en `dimension / stride` groupes contigus, et les plans de bits de chaque groupe sont stockés dans des flux distincts. Cela permet, lors d’une recherche sur les `D` premières dimensions (où `D` est un multiple de `stride`), de ne lire que les flux des groupes couvrant ces dimensions, ce qui est utile pour les Matryoshka embeddings.

<div id="creating-qbit">
  ## Création de QBit
</div>

Utilisation du type `QBit` dans la définition d’une colonne de la table :

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO test VALUES (1, [1, 2, 3, 4, 5, 6, 7, 8]), (2, [9, 10, 11, 12, 13, 14, 15, 16]);
SELECT vec FROM test ORDER BY id;
```

```text theme={null}
┌─vec──────────────────────┐
│ [1,2,3,4,5,6,7,8]        │
│ [9,10,11,12,13,14,15,16] │
└──────────────────────────┘
```

<div id="converting-arrays-to-qbit">
  ## Conversion de tableaux en QBit
</div>

Les tableaux sont convertis en `QBit` lorsque leur longueur correspond à la dimension de `QBit`. Le type des éléments du tableau n’a pas besoin de correspondre à celui de `QBit`. Tout type d’élément numérique y est converti automatiquement. Cela vous permet de transférer directement une colonne d’embeddings existante vers une colonne `QBit` :

```sql theme={null}
CREATE TABLE embeddings (id UInt32, embedding Array(Float32)) ENGINE = Memory;
INSERT INTO embeddings VALUES (1, [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]), (2, [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]);

CREATE TABLE vectors (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO vectors SELECT id, embedding FROM embeddings;

SELECT * FROM vectors ORDER BY id;
```

```text theme={null}
┌─id─┬─vec───────────────────────────────┐
│  1 │ [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8] │
│  2 │ [0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1] │
└────┴───────────────────────────────────┘
```

La conversion fonctionne également explicitement avec `CAST`, par exemple `CAST(embedding AS QBit(Float32, 8))`.

<div id="converting-qbit-to-arrays">
  ## Conversion de QBit en tableaux
</div>

La conversion inverse reconstitue le vecteur d’origine à partir de la représentation transposée bit à bit. Ainsi, convertir un `QBit` en `Array` renvoie les valeurs stockées. C’est l’inverse de [la conversion de tableaux en `QBit`](#converting-arrays-to-qbit) :

```sql theme={null}
SELECT [1, 2, 3, 4]::QBit(Float32, 4)::Array(Float32) AS vec;
```

```text theme={null}
┌─vec───────┐
│ [1,2,3,4] │
└───────────┘
```

Le tableau reconstruit utilise le type d’élément du `QBit`, puis ses éléments sont convertis dans le type d’élément du tableau demandé. Une conversion de type qui modifie également le type d’élément, comme de `QBit(Float32, N)` vers `Array(Float64)`, fonctionne donc elle aussi.

Un aller-retour `Array` -> `QBit` -> `Array` est sans perte pour `Int8`, `Float32` et `Float64`. Pour `BFloat16`, il correspond à une conversion directe en `BFloat16` — la seule précision perdue est celle propre à `BFloat16`.

Lorsque la `dimension` n’est pas un multiple de 8, les éléments de remplissage de fin présents dans la représentation interne sont supprimés, de sorte que le résultat comporte toujours exactement `dimension` éléments.

<div id="converting-between-qbit-types">
  ## Conversion entre les types QBit
</div>

Un `QBit` peut être converti dans un autre `QBit` tant que la `dimension` (le nombre d’éléments du vecteur) reste identique. Le `element_type` et le `stride` peuvent tous deux changer ; en revanche, une conversion vers un `QBit` ayant une `dimension` différente lève une exception, car cela modifierait le vecteur lui-même.

Modifier le `element_type` reconstruit le vecteur et convertit chaque élément vers le nouveau type, exactement comme pour la conversion `Array` correspondante : l’élargissement (par exemple de `QBit(Float32, N)` vers `QBit(Float64, N)`) est exact, tandis que le rétrécissement entraîne une perte de précision, comme avec une conversion `Array` restrictive.

```sql theme={null}
SELECT [1, 2, 3, 4]::QBit(Float32, 4)::QBit(Float64, 4) AS vec;
```

```text theme={null}
┌─vec───────┐
│ [1,2,3,4] │
└───────────┘
```

Modifier uniquement le [`stride`](#strides) (en conservant le même `element_type`) regroupe différemment les plans de bits stockés sans toucher aux valeurs ; l'opération est donc toujours sans perte :

```sql theme={null}
SELECT range(16)::Array(Float32)::QBit(Float32, 16)::QBit(Float32, 16, 8)::Array(Float32)
     = range(16)::Array(Float32) AS is_lossless;
```

```text theme={null}
┌─is_lossless─┐
│           1 │
└─────────────┘
```

<div id="qbit-subcolumns">
  ## Sous-colonnes QBit
</div>

`QBit` implémente un mécanisme d’accès par sous-colonnes qui vous permet d’accéder à chaque plan de bits des vecteurs stockés. Chaque position de bit est accessible à l’aide de la syntaxe `.N`, où `N` correspond à la position du bit :

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(Float32, 8)) ENGINE = Memory;
INSERT INTO test VALUES (1, [0, 0, 0, 0, 0, 0, 0, 0]);
INSERT INTO test VALUES (1, [-0, -0, -0, -0, -0, -0, -0, -0]);
SELECT bin(vec.1) FROM test;
```

```text theme={null}
┌─bin(tupleElement(vec, 1))─┐
│ 00000000                  │
│ 11111111                  │
└───────────────────────────┘
```

Le nombre de sous-colonnes accessibles dépend du type d’élément (et, en cas de découpage en strides, du nombre de groupes de stride) :

* `Int8` : 8 sous-colonnes par groupe de stride (1-8)
* `BFloat16` : 16 sous-colonnes par groupe de stride (1-16)
* `Float32` : 32 sous-colonnes par groupe de stride (1-32)
* `Float64` : 64 sous-colonnes par groupe de stride (1-64)

Les sous-colonnes suivent un ordre par groupe : en général, `vec.N` lit le plan de bits `(N-1) % element_size` du groupe de stride `(N-1) / element_size`. Par exemple, avec `QBit(BFloat16, 4096, 1024)`, les 4096 dimensions sont réparties en 4 groupes de 1024, il y a donc 64 sous-colonnes : `vec.1` … `vec.16` sont les plans de bits du premier groupe de stride (dimensions 1–1024), `vec.17` … `vec.32` appartiennent au deuxième groupe (dimensions 1025–2048), et ainsi de suite.

<div id="strides">
  ## Strides
</div>

Par défaut, un `QBit` stocke chaque plan de bits dans un flux unique couvrant l’ensemble des dimensions `dimension`, de sorte qu’une recherche lit toujours les plans de bits complets sur tout le vecteur. Le paramètre facultatif `stride` partitionne les dimensions `dimension` en `dimension / stride` groupes contigus et stocke les plans de bits de chaque groupe dans des flux distincts. Cela permet à une recherche portant uniquement sur les `D` premières dimensions (où `D` est un multiple de `stride`) de ne lire que les flux des groupes couvrant ces dimensions — ce qui est utile pour les [Matryoshka embeddings](https://arxiv.org/abs/2205.13147), où les premières dimensions forment un embedding exploitable de dimension inférieure.

```sql theme={null}
CREATE TABLE test (id UInt32, vec QBit(BFloat16, 4096, 1024)) ENGINE = MergeTree ORDER BY id;
```

Ici, les 4096 dimensions sont réparties en 4 groupes de 1024. Les sous-colonnes suivent un ordre par groupe : avec `BFloat16` (16 plans de bits), `vec.1` … `vec.16` correspondent aux 16 plans de bits du premier groupe de stride (dimensions 1–1024), `vec.17` … `vec.32` appartiennent au deuxième groupe (dimensions 1025–2048), et ainsi de suite. De manière générale, `vec.N` lit le plan de bits `(N-1) % element_size` du groupe de stride `(N-1) / element_size`.

Pour exécuter une recherche à dimension réduite, indiquez le nombre de dimensions à lire comme quatrième argument des fonctions de distance transposées (voir ci-dessous). Le vecteur de référence doit contenir au moins ce nombre d’éléments (tout élément supplémentaire en fin de vecteur est ignoré), et cette valeur doit être un multiple de `stride`.

<div id="vector-search-functions">
  ## Fonctions de recherche vectorielle
</div>

Voici les fonctions de distance pour la recherche de similarité vectorielle qui utilisent le type de données `QBit` :

* [`L2DistanceTransposed`](/docs/fr/reference/functions/regular-functions/distance-functions#L2DistanceTransposed)
* [`cosineDistanceTransposed`](/docs/fr/reference/functions/regular-functions/distance-functions#cosineDistanceTransposed)
* [`dotProductTransposed`](/docs/fr/reference/functions/regular-functions/distance-functions#dotProductTransposed)

Pour un `QBit` avec stride, ces fonctions acceptent un quatrième argument facultatif, `used_dims` — le nombre de premières dimensions à lire —, qui lit uniquement les groupes de stride couvrant ces dimensions. Le vecteur de référence doit comporter au moins `used_dims` éléments (tout élément supplémentaire en fin de vecteur est ignoré, de sorte qu'un vecteur de requête de taille complète peut être réutilisé pour une recherche à dimension réduite sans devoir le tronquer au préalable), et `used_dims` doit être un multiple de `stride`.
