Skip to main content
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:
  • 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.

Crear QBit

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

Conversión de arrays a QBit

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:
La conversión también se puede realizar explícitamente con CAST, por ejemplo CAST(embedding AS QBit(Float32, 8)).

Conversión de QBit a arrays

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

Conversión entre tipos de QBit

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.
Cambiar solo el stride (manteniendo el mismo element_type) reagrupa los planos de bits almacenados sin modificar los valores, por lo que nunca implica pérdida de datos:

Subcolumnas de QBit

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:
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.1vec.16 son los planos de bits del primer grupo de stride (dimensiones 1–1024), vec.17vec.32 pertenecen al segundo grupo (dimensiones 1025–2048), y así sucesivamente.

Strides

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, donde las dimensiones iniciales forman un embedding utilizable de menor dimensionalidad.
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.1vec.16 son los 16 planos de bits del primer grupo de stride (dimensiones 1–1024), vec.17vec.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.

Funciones de búsqueda vectorial

Estas son las funciones de distancia para la búsqueda de similitud vectorial que utilizan el tipo de dato QBit: 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.
Última modificación el 23 de julio de 2026