> ## 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.

> Documentación del tipo de dato QBit en ClickHouse, que permite una cuantización de grano fino para la búsqueda vectorial aproximada

# Tipo de dato QBit

El tipo de dato `QBit` reorganiza el almacenamiento de vectores para acelerar las búsquedas aproximadas. En lugar de almacenar juntos los elementos de cada vector, agrupa las mismas posiciones de bits en todos los vectores.
Esto permite almacenar los vectores con precisión completa y, al mismo tiempo, elegir el nivel de cuantización de grano fino en el momento de la búsqueda: leer menos bits para reducir el I/O y acelerar los cálculos, o más bits para obtener mayor precisión. Obtienes las ventajas de velocidad de la cuantización —menos transferencia de datos y menos cómputo—, pero todos los datos originales siguen disponibles cuando se necesitan.

Para declarar una columna de tipo `QBit`, usa la siguiente sintaxis:

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

* `element_type` – el tipo de cada elemento del vector. Los tipos permitidos son `Int8`, `BFloat16`, `Float32` y `Float64`
* `dimension` – la cantidad de elementos de cada vector
* `stride` – opcional. La cantidad de dimensiones almacenadas juntas en un grupo de streams. Cuando se omite, el valor predeterminado es `dimension` (un solo grupo). Cuando se proporciona, `dimension` debe ser un múltiplo de `stride` y, cuando `stride` es menor que `dimension`, `stride` debe ser un múltiplo de 8. Las `dimension` dimensiones se dividen en `dimension / stride` grupos contiguos, y los planos de bits de cada grupo se almacenan en streams separados. Esto permite que una búsqueda en las primeras `D` dimensiones (donde `D` es un múltiplo de `stride`) lea solo los streams de los grupos que abarcan esas dimensiones, lo que resulta útil para los embeddings Matryoshka.

<div id="creating-qbit">
  ## Crear QBit
</div>

Uso del tipo `QBit` en la definición de una columna de tabla:

```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">
  ## Conversión de arrays a QBit
</div>

Los arrays se convierten en `QBit` cuando la longitud del array coincide con la dimensión de `QBit`. El tipo de elemento del array no tiene que coincidir con el tipo de elemento de `QBit`. Cualquier tipo de elemento numérico se convierte automáticamente a este. Esto permite mover una columna existente de embeddings directamente a una columna `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 conversión también se puede realizar explícitamente con `CAST`, por ejemplo `CAST(embedding AS QBit(Float32, 8))`.

<div id="converting-qbit-to-arrays">
  ## Conversión de QBit a arrays
</div>

La conversión inversa reconstruye el vector original a partir de la representación con bits transpuestos, por lo que convertir un `QBit` a un `Array` devuelve los valores almacenados. Esto es lo inverso de [convertir arrays a `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] │
└───────────┘
```

El array reconstruido usa el tipo de elemento de `QBit`, y luego sus elementos se convierten al tipo de elemento del array solicitado. Por lo tanto, también funciona un cast que además cambia el tipo de elemento, como de `QBit(Float32, N)` a `Array(Float64)`.

Un recorrido de ida y vuelta `Array` -> `QBit` -> `Array` no pierde información para `Int8`, `Float32` y `Float64`. En el caso de `BFloat16`, coincide con una conversión directa a `BFloat16`: la única precisión que se pierde es la propia de `BFloat16`.

Cuando la `dimension` no es un múltiplo de 8, los elementos de relleno finales presentes en la representación interna se descartan, por lo que el resultado siempre tiene exactamente `dimension` elementos.

<div id="converting-between-qbit-types">
  ## Conversión entre tipos de `QBit`
</div>

Un `QBit` puede convertirse en otro `QBit` siempre que la `dimension` (el número de elementos del vector) siga siendo la misma. Tanto `element_type` como `stride` pueden cambiar; convertirlo a un `QBit` con una `dimension` distinta produce una excepción, porque eso cambiaría el propio vector.

Cambiar el `element_type` reconstruye el vector y convierte cada elemento al nuevo tipo, exactamente igual que en la conversión correspondiente de `Array`: una ampliación (por ejemplo, de `QBit(Float32, N)` a `QBit(Float64, N)`) es exacta, mientras que una reducción pierde precisión del mismo modo que lo haría una conversión restrictiva de `Array`.

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

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

Cambiar solo el [`stride`](#strides) (manteniendo el mismo `element_type`) reagrupa los planos de bits almacenados sin modificar los valores, por lo que nunca implica pérdida de datos:

```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">
  ## Subcolumnas de QBit
</div>

`QBit` implementa un patrón de acceso a subcolumnas que permite acceder a planos de bits individuales de los vectores almacenados. Se puede acceder a cada posición de bit mediante la sintaxis `.N`, donde `N` es la posición del 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                  │
└───────────────────────────┘
```

La cantidad de subcolumnas accesibles depende del tipo de elemento (y, cuando se usa `stride`, de la cantidad de grupos de stride):

* `Int8`: 8 subcolumnas por grupo de stride (1-8)
* `BFloat16`: 16 subcolumnas por grupo de stride (1-16)
* `Float32`: 32 subcolumnas por grupo de stride (1-32)
* `Float64`: 64 subcolumnas por grupo de stride (1-64)

Las subcolumnas siguen un orden principal por grupo: en general, `vec.N` lee el plano de bits `(N-1) % element_size` del grupo de stride `(N-1) / element_size`. Por ejemplo, con `QBit(BFloat16, 4096, 1024)` las 4096 dimensiones se dividen en 4 grupos de 1024, por lo que hay 64 subcolumnas: `vec.1` … `vec.16` son los planos de bits del primer grupo de stride (dimensiones 1–1024), `vec.17` … `vec.32` pertenecen al segundo grupo (dimensiones 1025–2048), y así sucesivamente.

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

De forma predeterminada, `QBit` almacena cada plano de bits como un único stream que abarca todas las dimensiones `dimension`, por lo que una búsqueda siempre lee planos de bits completos de todo el vector. El parámetro opcional `stride` divide las dimensiones `dimension` en `dimension / stride` grupos contiguos y almacena los planos de bits de cada grupo en streams separados. Esto permite que una búsqueda solo sobre las primeras `D` dimensiones (donde `D` es un múltiplo de `stride`) lea únicamente los streams de los grupos que cubren esas dimensiones, lo que resulta útil para [embeddings Matryoshka](https://arxiv.org/abs/2205.13147), donde las dimensiones iniciales forman un embedding utilizable de menor dimensionalidad.

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

Aquí, las 4096 dimensiones se dividen en 4 grupos de 1024. Las subcolumnas siguen un orden principal por grupo: con `BFloat16` (16 planos de bits), `vec.1` … `vec.16` son los 16 planos de bits del primer grupo de stride (dimensiones 1–1024), `vec.17` … `vec.32` pertenecen al segundo grupo (dimensiones 1025–2048), y así sucesivamente. En general, `vec.N` lee el plano de bits `(N-1) % element_size` del grupo de stride `(N-1) / element_size`.

Para ejecutar una búsqueda de dimensión reducida, pase el número de dimensiones que se van a leer como cuarto argumento de las funciones de distancia transpuestas (consulte más abajo). El vector de referencia debe tener al menos ese número de elementos (se ignoran los elementos adicionales al final), y el valor debe ser un múltiplo de `stride`.

<div id="vector-search-functions">
  ## Funciones de búsqueda vectorial
</div>

Estas son las funciones de distancia para la búsqueda de similitud vectorial que utilizan el tipo de dato `QBit`:

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

Para un `QBit` con stride, estas funciones aceptan un cuarto argumento opcional, `used_dims` —el número de dimensiones iniciales que se deben leer—, que hace que solo se lean los grupos de stride que cubren esas dimensiones. El vector de referencia debe tener al menos `used_dims` elementos (cualquier elemento adicional al final se ignora, por lo que se puede reutilizar un vector de consulta de tamaño completo para una búsqueda de dimensión reducida sin tener que recortarlo primero), y `used_dims` debe ser un múltiplo de `stride`.
