Índices de búsqueda

En esta página, se describe cómo agregar índices de búsqueda a las tablas. Los índices de búsqueda son necesarios para crear la estructura de una tabla necesario para permitir una búsqueda en el texto completo en Spanner

Índices de búsqueda en el texto completo

Puedes crear un índice de búsqueda en cualquier columna que quieras crear disponibles para las búsquedas en el texto completo. Para crear un índice de búsqueda, usa el CREATE SEARCH INDEX de DDL o actualiza una con la Declaración de DDL ALTER SEARCH INDEX. Spanner crea y mantiene automáticamente el índice de búsqueda, lo que incluye agregar y actualizar los datos en el índice de búsqueda apenas cambian en la base de datos.

Un índice de búsqueda puede estar particionada o no particionada, según el tipo de consultas que quieres acelerar.

  • Un ejemplo de cuándo un índice particionado es la mejor opción es cuando consulta un buzón de correo electrónico. Cada consulta se restringe a un buzón de correo.

  • Un ejemplo de cuándo una consulta no particionada es la mejor opción es cuando Si hay una consulta en todas las categorías de productos de un catálogo de productos.

Además de la búsqueda en el texto completo, los índices de búsqueda de Spanner admiten lo siguiente:

  • Las búsquedas de subcadenas, que son un tipo de consulta que busca una consulta más corta cadena (la subcadena) dentro de un cuerpo de texto más grande.
  • Aceleración para las consultas que tienen expresiones de concordancia exacta y numéricas.
  • Combinación de condiciones en cualquier subconjunto de datos indexados en un solo análisis de índice.

Mientras que los índices de búsqueda admiten el uso de datos no textuales, como números y cadenas de concordancia exacta, el caso de uso más común para un índice de búsqueda es indexar texto en un documento.

Para mostrar las capacidades de los índices de búsqueda, supón que hay una tabla que almacena información sobre los álbumes de música:

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX)
) PRIMARY KEY(AlbumId);

Spanner tiene varias funciones de asignación de tokens que crean tokens. Para modificar la tabla anterior y permitir que los usuarios ejecuten una búsqueda en el texto completo para encontrar títulos de álbumes, usa la función TOKENIZE_FULLTEXT para crear tokens a partir de los títulos de los álbumes. Luego, crea una columna que use el tipo de datos TOKENLIST. para contener el resultado de la asignación de token de TOKENIZE_FULLTEXT. En este ejemplo, creamos la columna AlbumTitle_Tokens.

ALTER TABLE Albums
  ADD COLUMN AlbumTitle_Tokens TOKENLIST
  AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN;

En el siguiente ejemplo, se usa el DDL CREATE SEARCH INDEX para crear un índice de búsqueda (AlbumsIndex) en los tokens de AlbumTitle (AlbumTitle_Tokens):

CREATE SEARCH INDEX AlbumsIndex
  ON Albums(AlbumTitle_Tokens);

Después de agregar el índice de búsqueda, usa consultas en SQL para encontrar los álbumes que coincidan los criterios de búsqueda. Por ejemplo:

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")

Coherencia de los datos

Cuando se crea un índice, Spanner usa procesos automatizados para reabastecerlos para garantizar la coherencia. Cuando se confirman las escrituras, los índices se actualizan en la misma transacción. Spanner automáticamente y hace verificaciones de la coherencia de los datos.

Buscar definiciones de esquema de índice

Los índices de búsqueda se definen en una o más columnas TOKENLIST de una tabla. Búsqueda los índices tienen los siguientes componentes:

  • Tabla base: Es la tabla de Spanner que necesita indexación.
  • Columna TOKENLIST: Es una colección de columnas que definen los tokens. que necesitan indexación. El orden de estas columnas no es importante.

Por ejemplo, en la siguiente instrucción, la tabla base es Álbumes. TOKENLIST las columnas se crean en AlbumTitle (AlbumTitle_Tokens) y Rating Rating_Tokens.

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  SingerId INT64 NOT NULL,
  ReleaseTimestamp INT64 NOT NULL,
  AlbumTitle STRING(MAX),
  Rating FLOAT64,
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
  Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN
) PRIMARY KEY(AlbumId);

Usa la siguiente declaración CREATE SEARCH INDEX para crear un índice de búsqueda con los tokens para AlbumTitle y Rating:

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens, Rating_Tokens)
PARTITION BY SingerId
ORDER BY ReleaseTimestamp DESC

Los índices de búsqueda tienen las siguientes opciones:

  • Particiones: Es un grupo opcional de columnas que dividen el índice de búsqueda. Consultar un índice particionado suele ser mucho más eficiente que consultar un índice no particionado. Para obtener más información, consulta Índices de búsqueda de particiones.
  • Columna de orden de clasificación: Es una columna INT64 opcional que establece el orden de recuperación del índice de búsqueda. Para ver más información, consulta Orden de clasificación del índice de búsqueda:
  • Intercalación: al igual que los índices secundarios, puedes intercalar los índices de búsqueda. Los índices de búsqueda intercalados usan menos recursos para escribir y unir tabla base. Para obtener más información, consulta Búsqueda intercalada. índices.
  • Cláusula de opciones: Una lista de pares clave-valor que anula el valor predeterminado del índice de búsqueda.

Para obtener más información, consulta la referencia CREATE SEARCH INDEX.

Diseño interno de índices de búsqueda

Un elemento importante de la representación interna de los índices de búsqueda es un docid, que sirve como representación eficiente en el almacenamiento de la clave primaria de la tabla base, que puede ser arbitrariamente larga. También es lo que crea la para el diseño de datos internos de acuerdo con el ORDER BY proporcionado por el usuario columnas de la CREATE SEARCH INDEX. Se representa como uno o dos números enteros de 64 bits.

Los índices de búsqueda se implementan internamente como una asignación de dos niveles:

  1. Tokens para Docids
  2. Docids a las claves primarias de la tabla base

Este esquema permite ahorrar mucho almacenamiento gracias a Spanner no necesita almacenar la clave primaria completa de la tabla base para cada Par de <token, document>.

Existen dos tipos de índices físicos que implementan los dos niveles mapeo:

  1. Un índice secundario que asigna claves de partición y un docid a la tabla base clave primaria. En el ejemplo de la sección anterior, esto asigna {SingerId, ReleaseTimestamp, uid} a {SingerId, AlbumId}. El índice secundario también almacena todas las columnas especificadas en la cláusula STORING de CREATE SEARCH INDEX.
  2. Los índices de tokens asignan tokens a docids, similar a los índices invertidos en en la literatura sobre recuperación de información. Spanner mantiene un un índice de token separado para cada TOKENLIST del índice de búsqueda. Desde el punto de vista lógico, Los índices de tokens mantienen listas de docids para cada token en cada partición. (conocidas en la recuperación de información como listas de publicaciones). Las listas están ordenadas. por tokens para una recuperación rápida y, dentro de las listas, docid se usa para ordenar. Los índices de tokens individuales son un detalle de la implementación que no se expone mediante APIs de Spanner.

Spanner admite las siguientes cuatro opciones de docid.

Índice de la Búsqueda DOCID Comportamiento
La cláusula ORDER BY se omite para el índice de búsqueda. { uid } Spanner agrega un valor único oculto (UID) para identificar cada fila.
ORDER BY column { column, uid } Spanner agrega la columna de UID como un tiebreaker entre filas con los mismos valores de column dentro de una partición.
ORDER BY column ... OPTIONS (disable_automatic_uid_column=true) { column } No se agrega la columna UID. Los valores column deben ser únicos dentro de una partición.
ORDER BY column1, column2 ... OPTIONS (disable_automatic_uid_column=true) { column1, column2 } No se agrega la columna UID. La combinación de los valores column1 y column2 debe ser única dentro de una partición.

Notas de uso:

  • La columna de UID interna no se expone a través de Spanner en la API de Cloud.
  • En los índices donde no se agrega el UID, cualquier transacción fallará si se produce dos filas con la misma (partición,orden).

Por ejemplo, considera los siguientes datos:

AlbumId SingerId ReleaseTimestamp AlbumTitle
a1 1 997 Perro grande
a2 1 743 Gato grande

Suponiendo que la columna de preordenamiento está en orden ascendente, el contenido del token índice particionado por SingerId particiona el contenido del índice de token en el de la siguiente manera:

SingerId _token ReleaseTimestamp uid
1 grande 743 uid1
1 grande 997 uid2
1 gato 743 uid1
1 perro 997 uid2

Fragmentación del índice de la búsqueda

Cuando Spanner divide una tabla, distribuye los datos del índice de búsqueda para que todos los tokens de una fila de la tabla base están en la misma división. En otras palabras, el índice de búsqueda está fragmentado por documentos. Esta estrategia de fragmentación tiene implicaciones significativas en el rendimiento:

  1. La cantidad de servidores con los que se comunica cada transacción sigue constante, sin importar la cantidad de tokens o de tokens indexados TOKENLIST columnas.
  2. Se ejecutan consultas de búsqueda que involucran varias expresiones condicionales de forma independiente en cada división, lo que evita la sobrecarga de rendimiento asociada con una unión distribuida.

Los índices de búsqueda tienen dos modos de distribución:

  • Fragmentación uniforme (predeterminado). En la fragmentación uniforme, los datos indexados de cada se asigna de forma aleatoria a una división de índice de una partición.
  • Fragmentación por orden de clasificación. En la fragmentación por orden, los datos de cada fila de la tabla base se asigna a una división de índice de una partición basada en el ORDER BY columnas. Por ejemplo, en el caso de un orden descendente, todas las filas con el los valores de orden más altos aparecen en la primera división de índice de una partición y el siguiente grupo más alto de valores de orden en la siguiente división.

Estos modos de fragmentación vienen con una compensación entre los riesgos de generación de hotspots y el Costo de la consulta:

  • Los índices de búsqueda fragmentados por orden de clasificación son propensos a la generación de hotspots cuando el índice se ordenados por marca de tiempo. Para obtener más información, consulta Elige una clave primaria para prevenir hotspots. Por otro lado, cuando la carga de escritura aumenta en un rango de documentos, La fragmentación uniforme garantiza que el aumento se distribuya de manera uniforme entre fragmentos.
  • La división basada en cargas estándar crea divisiones adicionales que proporcionan la protección adecuada contra la generación de hotspots. La desventaja de la fragmentación uniforme es que que puede usar más recursos para algunos tipos de consultas.

El modo de fragmentación de un índice de búsqueda se configura con la cláusula OPTIONS:

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens, Rating_Tokens)
PARTITION BY SingerId
ORDER BY ReleaseTimestamp DESC
OPTIONS (sort_order_sharding = true);

Cuando se configura sort_order_sharding=false o no se especifica, el índice de búsqueda se crearse con la fragmentación uniforme.

Índices de búsqueda intercalada

Al igual que los índices secundarios, puedes intercalar los índices de búsqueda una tabla superior de la tabla base. El motivo principal para usar la búsqueda intercalada es ubicar los datos de la tabla base con los datos del índice para particiones pequeñas. Esta colocación oportunista tiene las siguientes ventajas:

  • Las escrituras no necesitan hacer una confirmación en dos fases.
  • Las uniones inversas del índice de búsqueda con la tabla base no se distribuyen.

Los índices de búsqueda intercaladas tienen las siguientes restricciones:

  1. Solo ordenadas fragmentadas índices se pueden intercalar.
  2. Los índices de búsqueda solo se pueden intercalar en tablas de nivel superior (no en tablas secundarias) tablas).
  3. Al igual que las tablas intercaladas y los índices secundarios, haz que la clave del tabla superior, un prefijo de las columnas PARTITION BY en la tabla índice de búsqueda.

En el siguiente ejemplo, se muestra cómo definir un índice de búsqueda intercalado:

CREATE TABLE Singers (
  SingerId INT64 NOT NULL
) PRIMARY KEY(SingerId);

CREATE TABLE Albums (
  SingerId INT64 NOT NULL,
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN
) PRIMARY KEY(SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
PARTITION BY SingerId
INTERLEAVE IN Singers
OPTIONS (sort_order_sharding = true);

Índices de búsqueda con filtro NULL

Los índices de búsqueda pueden usar la sintaxis WHERE column IS NOT NULL para excluir las filas de la tabla base. Se puede aplicar el filtrado NULL a claves de partición, ordena columnas de orden y columnas almacenadas. El filtrado NULL en las columnas de array almacenadas no es por lo que está permitido.

Ejemplo

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING Genre
WHERE Genre IS NOT NULL

La consulta debe especificar la condición de filtrado NULL (Genre IS NOT NULL para este ejemplo) en la cláusula WHERE. De lo contrario, el Optimizador de consultas no podrá para usar el índice de búsqueda. Para obtener más información, consulta Requisitos de las consultas en SQL.

Usa el filtrado NULL en una columna generada para excluir filas basadas en cualquiera criterios arbitrarios. Para obtener más información, consulta Crea un índice parcial con un columna generada.

¿Qué sigue?