Gestionar índices vectoriales
En este documento se describe cómo crear y gestionar índices vectoriales para acelerar las búsquedas vectoriales.
Un índice vectorial es una estructura de datos diseñada para que la función VECTOR_SEARCH
se ejecute de forma más eficiente, sobre todo en conjuntos de datos grandes.
Cuando se usa un índice, VECTOR_SEARCH
utiliza algoritmos de vecino más cercano aproximado (ANN) para reducir la latencia de las consultas y el coste computacional. Aunque ANN introduce un grado de aproximación, lo que significa que la recuperación puede no ser del 100%, las mejoras de rendimiento suelen ofrecer una ventaja para la mayoría de las aplicaciones.
Roles y permisos
Para crear un índice vectorial, necesitas el permiso de gestión de identidades y accesos bigquery.tables.createIndex
en la tabla en la que vas a crear el índice. Para eliminar un índice vectorial, necesitas el permiso bigquery.tables.deleteIndex
. Cada uno de los siguientes roles de gestión de identidades y accesos predefinidos incluye los permisos que necesitas para trabajar con índices vectoriales:
- Propietario de datos de BigQuery (
roles/bigquery.dataOwner
) - Editor de datos de BigQuery (
roles/bigquery.dataEditor
)
Elige un tipo de índice de vectores
BigQuery ofrece dos tipos de índices de vectores, IVF y TreeAH, cada uno de los cuales admite diferentes casos prácticos. BigQuery admite la creación de lotes para la búsqueda de vectores procesando varias filas de los datos de entrada en la función VECTOR_SEARCH
.
En el caso de los lotes de consultas pequeños, se prefieren los índices IVF. Para grandes lotes de consultas, se prefieren los índices TreeAH, que se crean con el algoritmo ScaNN de Google.
Índice FIV
IVF es un índice de archivo invertido que usa un algoritmo de k-medias para agrupar los datos de vector en clústeres y, a continuación, particiona los datos de vector en función de esos clústeres. La función VECTOR_SEARCH
puede usar estas particiones para reducir la cantidad de datos que necesita leer para
determinar un resultado.
Índice TreeAH
El tipo de índice TreeAH recibe su nombre de la combinación de una estructura similar a un árbol y su uso de Asymmetric Hashing (AH), una técnica de cuantificación básica del algoritmo ScaNN subyacente. Un índice TreeAH funciona de la siguiente manera:
- La tabla base se divide en fragmentos más pequeños y fáciles de gestionar.
- Se entrena un modelo de clustering con el número de clústeres derivado de la opción
leaf_node_embedding_count
del argumentotree_ah_options
de la declaraciónCREATE VECTOR INDEX
. - Los vectores se comprimen con la cuantización de producto, una técnica que reduce el uso de memoria. Los vectores comprimidos se almacenan en las tablas de índice en lugar de los vectores originales, lo que reduce el tamaño de los índices de vectores.
- Cuando se ejecuta la función
VECTOR_SEARCH
, se calcula de forma eficiente una lista de candidatos para cada vector de consulta mediante el cifrado asimétrico, que se ha optimizado para el hardware para realizar cálculos de distancia aproximados. A continuación, se vuelven a puntuar y clasificar estos candidatos mediante las inserciones exactas.
El algoritmo TreeAH está optimizado para consultas por lotes que procesan cientos o más vectores de consulta. El uso de la cuantización de productos puede reducir significativamente la latencia y el coste, potencialmente en órdenes de magnitud en comparación con IVF. Sin embargo, debido al aumento de la sobrecarga, el algoritmo IVF puede ser más adecuado cuando tienes un número menor de vectores de consulta.
Te recomendamos que pruebes el tipo de índice TreeAH si tu caso de uso cumple los siguientes criterios:
La tabla contiene 200 millones de filas o menos.
Ejecutas con frecuencia consultas por lotes de gran tamaño que implican cientos o más vectores de consulta.
En el caso de las consultas de lotes pequeños con el tipo de índice TreeAH, VECTOR_SEARCH
podría
volver a
la búsqueda por fuerza bruta.
Cuando esto ocurre, se proporciona un
IndexUnusedReason
para explicar por qué no se ha utilizado el índice vectorial.
Crear un índice vectorial IVF
Para crear un índice vectorial IVF, usa la instrucción del lenguaje de definición de datos (DDL) CREATE VECTOR INDEX
:
Ve a la página BigQuery.
En el editor de consultas, ejecuta la siguiente instrucción SQL:
Para crear un índice vectorial IVF, sigue estos pasos:
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'IVF', distance_type = 'DISTANCE_TYPE', ivf_options = '{"num_lists":NUM_LISTS}')
Haz los cambios siguientes:
INDEX_NAME
: el nombre del índice vectorial que vas a crear. Como el índice siempre se crea en el mismo proyecto y conjunto de datos que la tabla base, no es necesario especificarlos en el nombre.DATASET_NAME
: el nombre del conjunto de datos que contiene la tabla.TABLE_NAME
: el nombre de la tabla que contiene la columna con los datos de los embeddings.COLUMN_NAME
: el nombre de una columna que contiene los datos de los embeddings. La columna debe ser de tipoARRAY<FLOAT64>
. La columna no puede tener ningún campo secundario. Todos los elementos de la matriz deben ser noNULL
y todos los valores de la columna deben tener las mismas dimensiones de matriz.STORED_COLUMN_NAME
: el nombre de una columna de nivel superior de la tabla que se va a almacenar en el índice vectorial. El tipo de columna no puede serRANGE
. Las columnas almacenadas no se usan si la tabla tiene una política de acceso a nivel de fila o si la columna tiene una etiqueta de política. Para obtener información sobre cómo habilitar las columnas almacenadas, consulta Almacenar columnas y prefiltrar.DISTANCE_TYPE
: especifica el tipo de distancia predeterminado que se va a usar al realizar una búsqueda de vectores con este índice. Los valores admitidos sonEUCLIDEAN
,COSINE
yDOT_PRODUCT
.EUCLIDEAN
es el valor predeterminado.La creación del índice siempre usa la distancia
EUCLIDEAN
para el entrenamiento, pero la distancia usada en la funciónVECTOR_SEARCH
puede ser diferente.Si especifica un valor para el argumento
distance_type
de la funciónVECTOR_SEARCH
, se usará ese valor en lugar del valorDISTANCE_TYPE
.NUM_LISTS
: un valorINT64
que especifica el número de listas que agrupa en clústeres el índice IVF y, a continuación, particiona los datos vectoriales. Este valor debe ser igual o inferior a 5000. Durante la indexación, los vectores se asignan a la lista correspondiente a su centroide de clúster más cercano. Si omite este argumento, BigQuery determinará un valor predeterminado en función de las características de sus datos. El valor predeterminado funciona bien en la mayoría de los casos prácticos.NUM_LISTS
controla la granularidad de la optimización de consultas. Cuanto mayor sea el valor, más listas se crearán, por lo que puedes definir la opciónfraction_lists_to_search
de la funciónVECTOR_SEARCH
para analizar un porcentaje menor del índice. Por ejemplo, analizar el 1% de 100 listas en lugar de analizar el 10% de 10 listas. Esto permite controlar mejor la velocidad de búsqueda y la recuperación, pero aumenta ligeramente el coste de indexación. Define el valor de este argumento en función de la precisión con la que necesites ajustar el ámbito de la consulta.
En el ejemplo siguiente se crea un índice vectorial en la columna embedding
de my_table
:
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF');
En el siguiente ejemplo se crea un índice vectorial en la columna embedding
de my_table
y se especifica el tipo de distancia que se va a usar y las opciones de IVF:
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF', distance_type = 'COSINE', ivf_options = '{"num_lists": 2500}')
Crear un índice de vectores TreeAH
Para crear un índice de vectores TreeAH, usa la instrucción del lenguaje de definición de datos (DDL) CREATE VECTOR INDEX
:
Ve a la página BigQuery.
En el editor de consultas, ejecuta la siguiente instrucción SQL:
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'TREE_AH', distance_type = 'DISTANCE_TYPE', tree_ah_options = '{"leaf_node_embedding_count":LEAF_NODE_EMBEDDING_COUNT, "normalization_type":"NORMALIZATION_TYPE"}')
Haz los cambios siguientes:
INDEX_NAME
: el nombre del índice vectorial que vas a crear. Como el índice siempre se crea en el mismo proyecto y conjunto de datos que la tabla base, no es necesario especificarlos en el nombre.DATASET_NAME
: el nombre del conjunto de datos que contiene la tabla.TABLE_NAME
: el nombre de la tabla que contiene la columna con los datos de los embeddings.COLUMN_NAME
: el nombre de una columna que contiene los datos de los embeddings. La columna debe ser de tipoARRAY<FLOAT64>
. La columna no puede tener ningún campo secundario. Todos los elementos de la matriz deben ser noNULL
y todos los valores de la columna deben tener las mismas dimensiones de matriz.STORED_COLUMN_NAME
: el nombre de una columna de nivel superior de la tabla que se va a almacenar en el índice vectorial. El tipo de columna no puede serRANGE
. Las columnas almacenadas no se usan si la tabla tiene una política de acceso a nivel de fila o si la columna tiene una etiqueta de política. Para obtener información sobre cómo habilitar las columnas almacenadas, consulta Almacenar columnas y prefiltrar.DISTANCE_TYPE
: argumento opcional que especifica el tipo de distancia predeterminado que se debe usar al realizar una búsqueda de vectores con este índice. Los valores admitidos sonEUCLIDEAN
,COSINE
yDOT_PRODUCT
.EUCLIDEAN
es el valor predeterminado.La creación del índice siempre usa la distancia
EUCLIDEAN
para el entrenamiento, pero la distancia usada en la funciónVECTOR_SEARCH
puede ser diferente.Si especifica un valor para el argumento
distance_type
de la funciónVECTOR_SEARCH
, se usará ese valor en lugar del valorDISTANCE_TYPE
.LEAF_NODE_EMBEDDING_COUNT
: un valorINT64
igual o superior a 500 que especifica el número aproximado de vectores de cada nodo hoja del árbol que crea el algoritmo TreeAH. El algoritmo TreeAH divide todo el espacio de datos en varias listas, y cada lista contiene aproximadamenteLEAF_NODE_EMBEDDING_COUNT
puntos de datos. Cuanto menor sea el valor, más listas se crearán con menos puntos de datos, mientras que, cuanto mayor sea el valor, menos listas se crearán con más puntos de datos. El valor predeterminado es 1000, que es adecuado para la mayoría de los conjuntos de datos.NORMALIZATION_TYPE
: un valor deSTRING
. Los valores admitidos sonNONE
yL2
. El valor predeterminado esNONE
. La normalización se produce antes de cualquier procesamiento, tanto para los datos de la tabla base como para los datos de la consulta, pero no modifica la columna de inserciónCOLUMN_NAME
enTABLE_NAME
. En función del conjunto de datos, el modelo de inserción y el tipo de distancia que se utilicen duranteVECTOR_SEARCH
, normalizar las inserciones puede mejorar la recuperación.
En el siguiente ejemplo se crea un índice de vectores en la columna embedding
de my_table
y se especifica el tipo de distancia que se va a usar y las opciones de TreeAH:
CREATE TABLE my_dataset.my_table(id INT64, embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS (index_type = 'TREE_AH', distance_type = 'EUCLIDEAN', tree_ah_options = '{"normalization_type": "L2"}');
Filtrado
En las siguientes secciones se explica cómo afectan los prefiltros y los postfiltros a los resultados de la búsqueda vectorial, así como la forma de prefiltrar usando columnas y particiones almacenadas en el índice vectorial.
Prefiltros y posfiltros
En las operaciones de BigQuery VECTOR_SEARCH
, tanto el prefiltrado como el posfiltrado sirven para acotar los resultados de búsqueda aplicando condiciones basadas en las columnas de metadatos asociadas a las inserciones de vectores. Es importante entender sus diferencias, su implementación y su impacto para optimizar el rendimiento, el coste y la precisión de las consultas.
El prefiltrado y el postfiltrado se definen de la siguiente manera:
- Prefiltrado: aplica las condiciones del filtro antes de que la búsqueda del vecino más cercano aproximado (ANN) realice cálculos de distancia en los vectores candidatos. De esta forma, se reduce el conjunto de vectores que se tienen en cuenta durante la búsqueda. Por lo tanto, el prefiltrado suele dar lugar a tiempos de consulta más rápidos y a un coste computacional menor, ya que la búsqueda de ANN evalúa menos candidatos potenciales.
- Después del filtrado: aplica las condiciones del filtro después de que la búsqueda de ANN haya identificado los
top_k
vecinos más cercanos iniciales. De esta forma, se refina el conjunto de resultados final en función de los criterios especificados.
La posición de la cláusula WHERE
determina si un filtro actúa como prefiltro o como postfiltro.
Para crear un prefiltro, la cláusula WHERE
de la consulta debe aplicarse al argumento de tabla base de la función VECTOR_SEARCH
.
El predicado debe aplicarse a una columna almacenada. De lo contrario, se convertirá en un filtro posterior.
En el siguiente ejemplo se muestra cómo crear un prefiltro:
-- Pre-filter on a stored column. The index speeds up the query. SELECT * FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE type = 'animal'), 'embedding', TABLE my_dataset.my_testdata); -- Filter on a column that isn't stored. The index is used to search the -- entire table, and then the results are post-filtered. You might see fewer -- than 5 matches returned for some embeddings. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, top_k => 5); -- Use pre-filters with brute force. The data is filtered and then searched -- with brute force for exact results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, options => '{"use_brute_force":true}');
Para crear un filtro posterior, la cláusula WHERE
de la consulta debe aplicarse fuera de la función VECTOR_SEARCH
para que filtre los resultados devueltos por la búsqueda.
En el siguiente ejemplo se muestra cómo crear un filtro posterior:
-- Use post-filters. The index is used, but the entire table is searched and -- the post-filtering might reduce the number of results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding', TABLE my_dataset.my_testdata, top_k => 5) WHERE base.type = 'animal'; SELECT base.id, distance FROM VECTOR_SEARCH( TABLE mydataset.base_table, 'embedding', (SELECT embedding FROM mydataset.query_table), top_k => 10 ) WHERE type = 'document' AND year > 2022
Cuando usa el post-filtrado o cuando los filtros de la tabla base que especifica hacen referencia a columnas no almacenadas y, por lo tanto, actúan como post-filtros, el conjunto de resultados final puede contener menos de top_k
filas (incluso cero filas) si el predicado es selectivo. Si necesitas un número específico de resultados después de aplicar los filtros, te recomendamos que especifiques un valor de top_k
más alto o que aumentes el valor de fraction_lists_to_search
en la llamada VECTOR_SEARCH
.
En algunos casos, sobre todo si el prefiltro es muy selectivo, el prefiltrado también puede reducir el tamaño del conjunto de resultados. Si esto ocurre, prueba a aumentar el valor de fraction_lists_to_search
en la llamada VECTOR_SEARCH
.
Prefiltrar con columnas almacenadas
Para mejorar aún más la eficiencia de tu índice vectorial, puedes especificar las columnas de tu tabla base que quieres almacenar en el índice vectorial. Si usas columnas almacenadas, puedes optimizar las consultas que llamen a la función VECTOR_SEARCH
de las siguientes formas:
En lugar de buscar en toda una tabla, puedes llamar a la función
VECTOR_SEARCH
en una instrucción de consulta que prefiltre la tabla base con una cláusulaWHERE
. Si tu tabla tiene un índice y solo filtras por columnas almacenadas, BigQuery optimiza la consulta filtrando los datos antes de realizar la búsqueda y, a continuación, usa el índice para buscar en el conjunto de resultados más pequeño. Si filtras por columnas que no están almacenadas, BigQuery aplica el filtro después de buscar en la tabla, es decir, filtros posteriores.La función
VECTOR_SEARCH
genera una estructura llamadabase
que contiene todas las columnas de la tabla base. Si no hay columnas almacenadas, se necesita una unión que puede ser costosa para recuperar las columnas almacenadas enbase
. Si usas un índice IVF y tu consulta solo selecciona columnas almacenadas debase
, BigQuery optimiza la consulta para eliminar esa unión. En el caso de los índices TreeAH, la combinación con la tabla base no se elimina. Las columnas almacenadas en los índices TreeAH solo se usan para prefiltrar.
Para almacenar columnas, inclúyalas en la cláusula STORING
de la instrucción CREATE VECTOR INDEX
.
Almacenar columnas aumenta el tamaño del índice vectorial, por lo que es mejor almacenar solo las columnas que se usan o filtran con más frecuencia.
En el siguiente ejemplo se crea un índice vectorial con columnas almacenadas y, a continuación, se ejecuta una consulta de búsqueda vectorial que solo selecciona columnas almacenadas:
-- Create a table that contains an embedding. CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>, type STRING, creation_time DATETIME, id INT64); -- Create a query table that contains an embedding. CREATE TABLE my_dataset.my_testdata(embedding ARRAY<FLOAT64>, test_id INT64); -- Create a vector index with stored columns. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) STORING (type, creation_time) OPTIONS (index_type = 'IVF'); -- Select only stored columns from a vector search to avoid an expensive join. SELECT query, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding' TABLE my_dataset.my_testdata);
Limitaciones de las columnas almacenadas
- Si se cambia el modo, el tipo o el esquema de una columna en la tabla base y es una columna almacenada en el índice vectorial, puede haber un retraso antes de que ese cambio se refleje en el índice vectorial. Hasta que se apliquen las actualizaciones al índice, las consultas de búsqueda de vectores usarán las columnas almacenadas modificadas de la tabla base.
- Si seleccionas una columna de tipo
STRUCT
de la salidaquery
de una consultaVECTOR_SEARCH
en una tabla que tiene un índice con columnas almacenadas, es posible que toda la consulta falle.
Prefiltrar con particiones
.Si la tabla en la que vas a crear el índice vectorial tiene particiones, también puedes crear particiones en el índice vectorial. La partición del índice vectorial tiene las siguientes ventajas:
- El recorte de particiones se aplica a los índices vectoriales, además de a las particiones de la tabla. La eliminación de particiones se produce cuando la búsqueda vectorial usa un filtro calificador en el valor de la columna con particiones. De esta forma, BigQuery puede analizar las particiones que coincidan con el filtro y omitir las demás. El recorte de particiones puede reducir los costes de E/S. Para obtener más información sobre la eliminación de particiones, consulta Consultar tablas con particiones.
- Es menos probable que la búsqueda vectorial no encuentre resultados si prefiltras por la columna de partición.
Solo puedes crear particiones de índices de vectores de TreeAH.
Solo se recomienda particionar un índice vectorial si usas el prefiltrado para limitar la mayoría de tus búsquedas vectoriales a unas pocas particiones.
Para crear un índice particionado, usa la cláusula PARTITION BY
de la
declaración CREATE VECTOR INDEX
. La cláusula PARTITION BY
que especifiques en la instrucción CREATE VECTOR INDEX
debe ser la misma que la cláusula PARTITION BY
especificada en la instrucción CREATE TABLE
de la tabla en la que estás creando el índice vectorial, tal como se muestra en el siguiente ejemplo:
-- Create a date-partitioned table. CREATE TABLE my_dataset.my_table( embeddings ARRAYid INT64, date DATE, ) PARTITION BY date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embeddings) PARTITION BY date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Si la tabla usa particiones de columna de intervalo de números enteros o de unidad de tiempo, la columna de partición se almacena en el índice vectorial, lo que aumenta el coste de almacenamiento.
Si se usa una columna de una tabla en las cláusulas STORING
y PARTITION BY
de la instrucción CREATE VECTOR INDEX
, la columna se almacena solo una vez.
Para usar la partición del índice vectorial, filtre por la columna de partición en la subconsulta de la tabla base de la instrucción VECTOR_SEARCH
. En el ejemplo siguiente, la tabla samples.items
tiene particiones por la columna produced_date
, por lo que la subconsulta de la tabla base de la instrucción VECTOR_SEARCH
filtra por la columna produced_date
:
SELECT query.id, base.id, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE produced_date = '2025-01-01'), 'embedding', TABLE samples.test, distance_type => 'COSINE', top_k => 10 );
Ejemplos
Crea un índice vectorial con particiones en una tabla con particiones por fecha y hora:
-- Create a datetime-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_date DATETIME, embeddings ARRAY) PARTITION BY produced_date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY produced_date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Crea un índice vectorial con particiones en una tabla con particiones por marca de tiempo:
-- Create a timestamp-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_time TIMESTAMP, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Crea un índice vectorial particionado en una tabla con particiones de rangos de números enteros:
-- Create a integer range-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Crea un índice vectorial particionado en una tabla con particiones por hora de ingestión:
-- Create a ingestion time-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
Limitaciones de los prefiltros
- No puedes usar vistas lógicas en el prefiltro.
- Si tu prefiltro contiene una subconsulta, puede interferir con el uso del índice.
Cuándo se indexan los datos
BigQuery gestiona por completo los índices vectoriales, que se actualizan automáticamente cuando cambia la tabla indexada.
La indexación es asíncrona. Hay un retraso entre el momento en que se añaden filas a la tabla base y el momento en que se reflejan en el índice. Sin embargo, la función VECTOR_SEARCH
sigue teniendo en cuenta todas las filas y no omite las filas sin indexar. La función busca los registros indexados mediante el índice y los registros que aún no se han indexado mediante una búsqueda de fuerza bruta.
Si creas un índice vectorial en una tabla que tiene un tamaño inferior a 10 MB, el índice vectorial no se rellenará. Del mismo modo, si eliminas datos de una tabla indexada y el tamaño de la tabla es inferior a 10 MB, el índice vectorial se inhabilitará temporalmente. En este caso, las consultas de búsqueda vectorial no usan el índice y el código indexUnusedReasons
de la sección vectorSearchStatistics
del recurso Job
es BASE_TABLE_TOO_SMALL
. Sin el índice,
VECTOR_SEARCH
recurre automáticamente a la fuerza bruta para encontrar los
vecinos más cercanos de las inserciones.
Si elimina la columna indexada de una tabla o cambia el nombre de la tabla, el índice vectorial se elimina automáticamente.
Monitorizar el estado de los índices vectoriales
Puedes monitorizar el estado de tus índices vectoriales consultando las vistas INFORMATION_SCHEMA
. Las siguientes vistas contienen metadatos sobre los índices vectoriales:
La vista
INFORMATION_SCHEMA.VECTOR_INDEXES
contiene información sobre los índices vectoriales de un conjunto de datos.Una vez que se haya completado la instrucción
CREATE VECTOR INDEX
, el índice debe rellenarse para que puedas usarlo. Puede usar las columnaslast_refresh_time
ycoverage_percentage
para verificar si un índice vectorial está listo. Si el índice vectorial no está listo, puedes seguir usando la funciónVECTOR_SEARCH
en una tabla, pero puede que funcione más lentamente sin el índice.La vista
INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS
contiene información sobre las columnas indexadas por vector de todas las tablas de un conjunto de datos.La
INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS
vista contiene información sobre las opciones que usan los índices vectoriales de un conjunto de datos.
Ejemplos de índices vectoriales
En el siguiente ejemplo se muestran todos los índices vectoriales activos de las tablas del conjunto de datos my_dataset
, ubicado en el proyecto my_project
. Incluye sus nombres, las instrucciones DDL usadas para crearlos y su porcentaje de cobertura. Si una tabla base indexada tiene menos de 10 MB, su índice no se rellena, en cuyo caso el valor de coverage_percentage
es 0.
SELECT table_name, index_name, ddl, coverage_percentage FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES WHERE index_status = 'ACTIVE';
El resultado es similar al siguiente:
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table_name | index_name | ddl | coverage_percentage | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table1 | indexa | CREATE VECTOR INDEX `indexa` ON `my_project.my_dataset.table1`(embeddings) | 100 | | | | OPTIONS (distance_type = 'EUCLIDEAN', index_type = 'IVF', ivf_options = '{"num_lists": 100}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table2 | indexb | CREATE VECTOR INDEX `indexb` ON `my_project.my_dataset.table2`(vectors) | 42 | | | | OPTIONS (distance_type = 'COSINE', index_type = 'IVF', ivf_options = '{"num_lists": 500}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+ | table3 | indexc | CREATE VECTOR INDEX `indexc` ON `my_project.my_dataset.table3`(vectors) | 98 | | | | OPTIONS (distance_type = 'DOT_PRODUCT', index_type = 'TREE_AH', | | | | | tree_ah_options = '{"leaf_node_embedding_count": 1000, "normalization_type": "NONE"}') | | +------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
Ejemplos de columnas de índice vectorial
La siguiente consulta extrae información sobre las columnas que tienen índices vectoriales:
SELECT table_name, index_name, index_column_name, index_field_path FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS;
El resultado es similar al siguiente:
+------------+------------+-------------------+------------------+ | table_name | index_name | index_column_name | index_field_path | +------------+------------+-------------------+------------------+ | table1 | indexa | embeddings | embeddings | | table2 | indexb | vectors | vectors | | table3 | indexc | vectors | vectors | +------------+------------+-------------------+------------------+
Ejemplos de opciones de índice vectorial
La siguiente consulta extrae información sobre las opciones de índice vectorial:
SELECT table_name, index_name, option_name, option_type, option_value FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS;
El resultado es similar al siguiente:
+------------+------------+------------------+------------------+-------------------------------------------------------------------+ | table_name | index_name | option_name | option_type | option_value | +------------+------------+------------------+------------------+-------------------------------------------------------------------+ | table1 | indexa | index_type | STRING | IVF | | table1 | indexa | distance_type | STRING | EUCLIDEAN | | table1 | indexa | ivf_options | STRING | {"num_lists": 100} | | table2 | indexb | index_type | STRING | IVF | | table2 | indexb | distance_type | STRING | COSINE | | table2 | indexb | ivf_options | STRING | {"num_lists": 500} | | table3 | indexc | index_type | STRING | TREE_AH | | table3 | indexc | distance_type | STRING | DOT_PRODUCT | | table3 | indexc | tree_ah_options | STRING | {"leaf_node_embedding_count": 1000, "normalization_type": "NONE"} | +------------+------------+------------------+------------------+-------------------------------------------------------------------+
Verificar el uso del índice vectorial
La información sobre el uso del índice vectorial está disponible en los metadatos del trabajo que ejecutó la consulta de búsqueda vectorial. Puedes ver los metadatos de las tareas mediante la consola Google Cloud , la herramienta de línea de comandos bq, la API de BigQuery o las bibliotecas de cliente.
Cuando usas la Google Cloud consola, puedes encontrar información sobre el uso del índice vectorial en los campos Modo de uso del índice vectorial y Motivos por los que no se usa el índice vectorial.
Cuando usas la herramienta bq o la API BigQuery, puedes encontrar información sobre el uso del índice vectorial en la sección VectorSearchStatistics
del recurso Job
.
El modo de uso del índice indica si se ha usado un índice vectorial. Para ello, se proporciona uno de los siguientes valores:
UNUSED
: no se ha usado ningún índice vectorial.PARTIALLY_USED
: algunas funciones deVECTOR_SEARCH
de la consulta usaban índices vectoriales y otras no.FULLY_USED
: cada funciónVECTOR_SEARCH
de la consulta usaba un índice vectorial.
Cuando el valor del modo de uso del índice es UNUSED
o PARTIALLY_USED
,
los motivos por los que no se ha usado el índice indican por qué no se han usado los índices vectoriales en la consulta.
Por ejemplo, los siguientes resultados devueltos por bq show --format=prettyjson -j my_job_id
muestran que no se ha usado el índice porque se ha especificado la opción use_brute_force
en la función VECTOR_SEARCH
:
"vectorSearchStatistics": { "indexUnusedReasons": [ { "baseTable": { "datasetId": "my_dataset", "projectId": "my_project", "tableId": "my_table" }, "code": "INDEX_SUPPRESSED_BY_FUNCTION_OPTION", "message": "No vector index was used for the base table `my_project:my_dataset.my_table` because use_brute_force option has been specified." } ], "indexUsageMode": "UNUSED" }
Opciones de gestión de índices
Para crear índices y que BigQuery los mantenga, tienes dos opciones:
- Usar el grupo de ranuras compartido predeterminado: si los datos que quieres indexar no superan el límite por organización, puedes usar el grupo de ranuras compartido gratuito para gestionar los índices.
- Usar tu propia reserva: para que la indexación de tus cargas de trabajo de producción más grandes sea más predecible y coherente, puedes usar tus propias reservas para gestionar los índices.
Usar slots compartidos
Si no has configurado tu proyecto para que use una reserva dedicada para la indexación, la gestión de índices se realiza en el grupo de ranuras compartido gratuito, sujeto a las siguientes restricciones.
Si añades datos a una tabla que provoca que el tamaño total de las tablas indexadas supere el límite de tu organización, BigQuery pausará la gestión de índices de esa tabla. Cuando esto ocurre, el campo index_status
de la vista INFORMATION_SCHEMA.VECTOR_INDEXES
muestra PENDING DISABLEMENT
y el índice se pone en cola para su eliminación. Mientras el índice está pendiente de inhabilitación, se sigue usando en las consultas y se te cobra por el almacenamiento del índice.
Una vez que se elimina el índice, el campo index_status
muestra el índice como TEMPORARILY DISABLED
. En este estado, las consultas no usan el índice y no se te cobra por el almacenamiento del índice. En este caso, el código IndexUnusedReason
es BASE_TABLE_TOO_LARGE
.
Si elimina datos de la tabla y el tamaño total de las tablas indexadas es inferior al límite por organización, se reanudará la gestión de índices. El campo index_status
de la vista INFORMATION_SCHEMA.VECTOR_INDEXES
es ACTIVE
, las consultas pueden usar el índice y se te cobra por el almacenamiento del índice.
Puedes usar la vista INFORMATION_SCHEMA.SEARCH_INDEXES_BY_ORGANIZATION
para ver el consumo actual en relación con el límite por organización de una región concreta, desglosado por proyectos y tablas.
BigQuery no garantiza la disponibilidad del grupo compartido ni el rendimiento de la indexación que veas. En el caso de las aplicaciones de producción, puede que te interese usar ranuras específicas para procesar los índices.
Usar tu propia reserva
En lugar de usar el grupo de ranuras compartido predeterminado, puedes designar tu propia reserva para indexar tus tablas. Si usas tu propia reserva, te aseguras de que las tareas de gestión de índices, como la creación, la actualización y las optimizaciones en segundo plano, tengan un rendimiento predecible y constante.
- No hay límites de tamaño de tabla cuando se ejecuta un trabajo de indexación en tu reserva.
- Usar tu propia reserva te ofrece flexibilidad en la gestión de índices. Si necesitas crear un índice muy grande o hacer una actualización importante en una tabla indexada, puedes añadir temporalmente más ranuras a la asignación.
Para indexar las tablas de un proyecto con una reserva designada, crea una reserva en la región en la que se encuentren tus tablas. A continuación, asigna el proyecto a la reserva con el valor job_type
definido como BACKGROUND
:
SQL
Usa la
CREATE ASSIGNMENT
instrucción DDL.
En la Google Cloud consola, ve a la página BigQuery.
En el editor de consultas, introduce la siguiente instrucción:
CREATE ASSIGNMENT `ADMIN_PROJECT_ID.region-LOCATION.RESERVATION_NAME.ASSIGNMENT_ID` OPTIONS ( assignee = 'projects/PROJECT_ID', job_type = 'BACKGROUND');
Haz los cambios siguientes:
ADMIN_PROJECT_ID
: el ID de proyecto del proyecto de administración que posee el recurso de reservaLOCATION
: la ubicación de la reservaRESERVATION_NAME
: el nombre de la reservaASSIGNMENT_ID
: el ID de la tareaEl ID debe ser único para el proyecto y la ubicación, empezar y terminar con una letra minúscula o un número, y contener solo letras minúsculas, números y guiones.
PROJECT_ID
: el ID del proyecto que contiene las tablas que se van a indexar. Este proyecto está asignado a la reserva.
Haz clic en
Ejecutar.
Para obtener más información sobre cómo ejecutar consultas, consulta Ejecutar una consulta interactiva.
bq
Usa el comando bq mk
:
bq mk \ --project_id=ADMIN_PROJECT_ID \ --location=LOCATION \ --reservation_assignment \ --reservation_id=RESERVATION_NAME \ --assignee_id=PROJECT_ID \ --job_type=BACKGROUND \ --assignee_type=PROJECT
Haz los cambios siguientes:
ADMIN_PROJECT_ID
: el ID del proyecto de administración que tiene el recurso de reserva.LOCATION
: la ubicación de la reservaRESERVATION_NAME
: el nombre de la reservaPROJECT_ID
: ID del proyecto que se va a asignar a esta reserva
Ver tus tareas de indexación
Se crea un nuevo trabajo de indexación cada vez que se crea o se actualiza un índice en una sola tabla. Para ver información sobre el trabajo, consulta las vistas INFORMATION_SCHEMA.JOBS*
. Puedes filtrar los trabajos de indexación configurando job_type IS NULL AND SEARCH(job_id, '`search_index`')
en la cláusula WHERE
de tu consulta. En el siguiente ejemplo se muestran los cinco trabajos de indexación más recientes del proyecto my_project
:
SELECT * FROM region-us.INFORMATION_SCHEMA.JOBS WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') ORDER BY creation_time DESC LIMIT 5;
Elige el tamaño de tu reserva
Para elegir el número de ranuras adecuado para tu reserva, debes tener en cuenta cuándo se ejecutan los trabajos de gestión de índices, cuántas ranuras utilizan y cómo es tu uso a lo largo del tiempo. BigQuery activa una tarea de gestión de índices en las siguientes situaciones:
- Crea un índice en una tabla.
- Los datos se modifican en una tabla indexada.
- El esquema de una tabla cambia y esto afecta a las columnas que se indexan.
- Los datos y los metadatos del índice se optimizan o actualizan periódicamente.
El número de ranuras que necesitas para un trabajo de gestión de índices en una tabla depende de los siguientes factores:
- El tamaño de la tabla
- La velocidad de ingestión de datos en la tabla
- La frecuencia de las instrucciones DML aplicadas a la tabla
- El retraso aceptable para crear y mantener el índice
- La complejidad del índice, que suele determinarse por los atributos de los datos, como el número de términos duplicados
Monitorizar el uso y el progreso
La mejor forma de evaluar el número de ranuras que necesitas para ejecutar de forma eficiente tus trabajos de gestión de índices es monitorizar la utilización de ranuras y ajustar el tamaño de la reserva en consecuencia. La siguiente consulta genera el uso diario de ranuras de las tareas de gestión de índices. En la región us-west1
solo se incluyen los últimos 30 días:
SELECT TIMESTAMP_TRUNC(job.creation_time, DAY) AS usage_date, -- Aggregate total_slots_ms used for index-management jobs in a day and divide -- by the number of milliseconds in a day. This value is most accurate for -- days with consistent slot usage. SAFE_DIVIDE(SUM(job.total_slot_ms), (1000 * 60 * 60 * 24)) AS average_daily_slot_usage FROM `region-us-west1`.INFORMATION_SCHEMA.JOBS job WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') GROUP BY usage_date ORDER BY usage_date DESC limit 30;
Si no hay suficientes ranuras para ejecutar trabajos de gestión de índices, un índice puede dejar de estar sincronizado con su tabla y los trabajos de indexación pueden fallar. En este caso, BigQuery vuelve a compilar el índice desde cero. Para evitar que el índice se desincronice, asegúrate de tener suficientes ranuras para admitir las actualizaciones del índice procedentes de la ingestión y la optimización de datos. Para obtener más información sobre cómo monitorizar el uso de las ranuras, consulta los gráficos de recursos de administrador.
Reconstruir un índice vectorial
Si los datos de una tabla cambian significativamente después de crear un índice vectorial, este puede perder eficiencia. Cuando un índice vectorial es menos eficiente, una consulta de búsqueda vectorial que inicialmente tenía una cobertura alta al usar el índice tendrá una cobertura menor, ya que la distribución de datos de la tabla base no se representa en el índice vectorial.
Si quieres mejorar la recuperación sin aumentar la latencia de las consultas de búsqueda, vuelve a compilar el índice vectorial. También puedes aumentar el valor de la opción fraction_lists_to_search
de la búsqueda vectorial para mejorar la recuperación, pero esto suele ralentizar la consulta de búsqueda.
Puedes usar la función VECTOR_INDEX.STATISTICS
para calcular cuánto han variado los datos de una tabla indexada entre el momento en que se creó un índice vectorial y el momento actual. Si los datos de la tabla han cambiado lo suficiente como para requerir una recompilación del índice vectorial, puede usar la instrucción ALTER VECTOR INDEX REBUILD
para recompilar el índice vectorial.
Sigue estos pasos para volver a compilar un índice vectorial:
Ve a la página BigQuery.
En el editor de consultas, ejecuta la siguiente instrucción SQL para comprobar la deriva de los datos de la tabla indexada:
SELECT * FROM VECTOR_INDEX.STATISTICS(TABLE DATASET_NAME.TABLE_NAME);
Haz los cambios siguientes:
DATASET_NAME
: el nombre del conjunto de datos que contiene la tabla indexada.TABLE_NAME
: el nombre de la tabla que contiene el índice vectorial.
La función devuelve un valor
FLOAT64
en el intervalo[0,1)
. Un valor más bajo indica una menor deriva. Por lo general, se considera que un valor de0.3
o superior es un cambio lo suficientemente significativo como para indicar que puede ser beneficioso volver a compilar un índice vectorial.Si la función
VECTOR_INDEX.STATISTICS
indica que la deriva de los datos de la tabla es significativa, ejecuta la siguiente instrucción SQL para volver a compilar el índice vectorial:ALTER VECTOR INDEX IF EXISTS INDEX_NAME ON DATASET_NAME.TABLE_NAME REBUILD;
Haz los cambios siguientes:
INDEX_NAME
: el nombre del índice vectorial que estás reconstruyendo.DATASET_NAME
: el nombre del conjunto de datos que contiene la tabla indexada.TABLE_NAME
: el nombre de la tabla que contiene el índice vectorial.
Eliminar un índice vectorial
Cuando ya no necesites un índice vectorial o quieras cambiar la columna indexada de una tabla, puedes eliminar el índice de esa tabla mediante la DROP VECTOR INDEX
declaración de DDL:
Ve a la página BigQuery.
En el editor de consultas, ejecuta la siguiente instrucción SQL:
DROP VECTOR INDEX INDEX_NAME ON DATASET_NAME.TABLE_NAME;
Haz los cambios siguientes:
INDEX_NAME
: el nombre del índice vectorial que quieres eliminar.DATASET_NAME
: el nombre del conjunto de datos que contiene la tabla indexada.TABLE_NAME
: el nombre de la tabla que contiene el índice vectorial.
Si se elimina una tabla indexada, su índice se elimina automáticamente.
Exportar incrustaciones a Vertex AI Vector Search
Para habilitar aplicaciones online con latencia ultrabaja, usa la integración de BigQuery con Vector Search de Vertex AI para importar tus inserciones de BigQuery en Vector Search y desplegar endpoints de baja latencia. Para obtener más información, consulta Importar datos de índice de BigQuery.
Siguientes pasos
- Para ver un resumen de los casos prácticos, los precios y las limitaciones de los índices vectoriales, consulta la introducción a la búsqueda vectorial.
- Consulta cómo realizar una búsqueda vectorial con la función
VECTOR_SEARCH
. - Consulta más información sobre la declaración
CREATE VECTOR INDEX
. - Prueba el tutorial Buscar incrustaciones con la búsqueda de vectores.