Descripción general de las consultas

En esta página, se describe la función SEARCH y sus diversas capacidades avanzadas, que se usan para realizar consultas de búsqueda de texto completo en tablas de Spanner.

Consultar un índice de búsqueda

Spanner proporciona la SEARCH función para usarla en consultas de índice de búsqueda. Un caso de uso de ejemplo sería una aplicación en la que los usuarios ingresan texto en un cuadro de búsqueda y la aplicación envía la entrada del usuario directamente a la función SEARCH. Luego, la función SEARCH usaría un índice de búsqueda para encontrar ese texto.

La función SEARCH requiere dos argumentos:

  • Un nombre de índice de búsqueda
  • Una búsqueda

La función SEARCH solo funciona cuando se define un índice de búsqueda. La función SEARCH se puede combinar con cualquier construcción de SQL arbitraria, como filtros, agregaciones o uniones.

La función SEARCH no se puede usar con consultas de transacción.

La siguiente consulta usa la función SEARCH para mostrar todos los álbumes que tienen friday o monday en el título:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')

PostgreSQL

En este ejemplo, se usa spanner.search.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'friday OR monday')

Búsqueda

Las búsquedas usan la sintaxis de búsqueda sin procesar de forma predeterminada. Se pueden especificar sintaxis alternativas con el SEARCH dialect argumento.

Dialecto rquery

El dialecto predeterminado es la búsqueda sin procesar. Spanner usa un lenguaje específico del dominio (DSL) llamado rquery.

El lenguaje rquery sigue las mismas reglas que el tokenizador de texto sin formato cuando divide la búsqueda de entrada en términos distintos. Esto incluye la segmentación de idiomas asiáticos.

Para obtener información sobre el uso de rquery, consulta la sintaxis de rquery.

Dialecto words

El dialecto words es similar a rquery, pero más simple. No usa ningún operador especial. Por ejemplo, OR se trata como un término de búsqueda en lugar de un operador de disyunción. Las comillas dobles se manejan como signos de puntuación en lugar de una búsqueda de frase y se ignoran.

Con el dialecto words, AND se aplica de forma implícita a todos los términos y es obligatorio durante la coincidencia. Sigue las mismas reglas que el tokenizador de texto sin formato cuando divide la búsqueda de entrada en términos.

Para obtener información sobre el uso del dialecto words, consulta la sintaxis de words.

Dialecto words_phrase

El dialecto words_phrase no usa ningún operador especial y todos los términos se tratan como una frase, lo que significa que los términos deben ser adyacentes y estar en el orden especificado.

Al igual que rquery, el dialecto words_phrase sigue las mismas reglas que el tokenizador de texto sin formato cuando divide la búsqueda de entrada en términos.

Para obtener información sobre el uso del dialecto words_phrase, consulta la sintaxis de la frase words.

Expande las búsquedas para aumentar los resultados relacionados

Puedes aumentar la probabilidad de encontrar resultados relevantes con las capacidades avanzadas de Spanner para expandir las búsquedas con términos relacionados, sinónimos y correcciones ortográficas. Estas capacidades incluyen lo siguiente:

Para obtener más información, consulta Búsqueda con mejora de consultas.

Requisitos de las consulta en SQL

Existen varias condiciones que debe cumplir una consulta en SQL para usar un índice de búsqueda. Si no se cumplen estas condiciones, la consulta usa un plan de consulta alternativo o falla si no existe un plan alternativo.

Las consultas deben cumplir con las siguientes condiciones:

  • La función SEARCH y SEARCH_SUBSTRING requieren un índice de búsqueda. Spanner no admite estas funciones en consultas en la tabla base ni en índices secundarios.

  • Los índices particionados deben tener todas las columnas de partición vinculadas por una condición de igualdad en la WHERE cláusula de la consulta.

    Por ejemplo, si un índice de búsqueda se define como PARTITION BY x, y, la consulta debe tener una conjunción en la cláusula WHERE de x = <parameter or constant> AND y = <parameter or constant>. El optimizador de consultas no considera ese índice de búsqueda si falta esa condición.

  • Todas las columnas TOKENLIST a las que hacen referencia los operadores SEARCH y SEARCH_SUBSTRING deben indexarse en el mismo índice de búsqueda.

    Por ejemplo, considera la siguiente definición de tabla e índice:

    GoogleSQL

    CREATE TABLE Albums (
        AlbumId STRING(MAX) NOT NULL,
        AlbumTitle STRING(MAX),
        AlbumStudio STRING(MAX),
        AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
        AlbumStudio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumStudio)) HIDDEN
    ) PRIMARY KEY(AlbumId);
    
    CREATE SEARCH INDEX AlbumsTitleIndex ON Albums(AlbumTitle_Tokens);
    CREATE SEARCH INDEX AlbumsStudioIndex ON Albums(AlbumStudio_Tokens);
    

    PostgreSQL

    CREATE TABLE albums (
        albumid character varying NOT NULL,
        albumtitle character varying,
        albumstudio character varying,
        albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
        albumstudio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumstudio)) VIRTUAL HIDDEN,
    PRIMARY KEY(albumid));
    
    CREATE SEARCH INDEX albumstitleindex ON albums(albumtitle_tokens);
    CREATE SEARCH INDEX albumsstudioindex ON albums(albumstudio_tokens);
    

    La siguiente consulta falla porque no hay un solo índice de búsqueda que indexe AlbumTitle_Tokens y AlbumStudio_Tokens:

    GoogleSQL

    SELECT AlbumId
    FROM Albums
    WHERE SEARCH(AlbumTitle_Tokens, @p1)
        AND SEARCH(AlbumStudio_Tokens, @p2)
    

    PostgreSQL

    En este ejemplo, se usan los parámetros de consulta $1 y $2, que están vinculados a “fast car” y “blue note”, respectivamente.

    SELECT albumid
    FROM albums
    WHERE spanner.search(albumtitle_tokens, $1)
        AND spanner.search(albumstudio_tokens, $2)
    
  • Si la columna de orden de clasificación admite valores nulos, tanto el esquema como la consulta deben excluir las filas en las que la columna de orden de clasificación es NULL. Para obtener más detalles, consulta Orden de clasificación del índice de búsqueda.

  • Si el índice de búsqueda se filtra como NULL, la consulta debe incluir la misma expresión de filtrado NULL que se usa en un índice. Consulta Índices de búsqueda filtrados como NULL para obtener más detalles.

  • Los índices de búsqueda y las funciones de búsqueda no se admiten en DML, DML particionado ni consultas particionadas.

  • Los índices de búsqueda y las funciones de búsqueda suelen usarse en transacciones de solo lectura. Si los requisitos de la aplicación permiten resultados obsoletos, es posible que puedas mejorar la latencia ejecutando búsquedas con una duración de obsolescencia de 10 segundos o más. Para obtener más información, consulta Lee datos obsoletos. Esto es muy útil para las búsquedas que se expanden a muchas divisiones de índice.

No se recomiendan los índices de búsqueda ni las funciones de búsqueda en transacciones de lectura y escritura. Durante la ejecución, las búsquedas bloquean una partición de índice completa; como resultado, una alta tasa de búsquedas en transacciones de lectura y escritura puede causar conflictos de bloqueo que provoquen picos de latencia. De forma predeterminada, los índices de búsqueda no se seleccionan automáticamente en las transacciones de lectura y escritura. Si se obliga a una consulta a usar un índice de búsqueda en una transacción de lectura y escritura, falla de forma predeterminada. También falla si la consulta contiene alguna de las funciones de búsqueda. Este comportamiento se puede anular con la sugerencia a nivel de instrucción @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} de GoogleSQL (pero las consultas aún son propensas a conflictos de bloqueo).

Una vez que se cumplen las condiciones de elegibilidad del índice, el optimizador de consultas intenta acelerar las condiciones de consulta que no son de texto (como Rating > 4). Si el índice de búsqueda no incluye la columna TOKENLIST adecuada, la condición no se acelera y sigue siendo una condición residual.

Parámetros de consulta

Los argumentos de búsqueda se especifican como un literal o un parámetro de consulta. Recomendamos usar parámetros de consulta para la búsqueda de texto completo en lugar de literales de cadena cuando los argumentos permiten el valor del parámetro de consulta.

Selección de índice

Por lo general, Spanner selecciona el índice más eficiente para una consulta mediante el modelado basado en costos. Sin embargo, la sugerencia FORCE_INDEX le indica explícitamente a Spanner que use un índice de búsqueda específico. Por ejemplo, a continuación, se muestra cómo obligar a Spanner a usar AlbumsIndex:

GoogleSQL

SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")

PostgreSQL

SELECT albumid
FROM albums/*@force_index=albumsindex*/
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')

Si el índice de búsqueda especificado no es apto, la consulta falla, incluso si hay otros índices de búsqueda aptos.

Fragmentos en los resultados de la búsqueda

Un fragmento es un fragmento de texto extraído de una cadena determinada que les da a los usuarios una idea de lo que contiene un resultado de la búsqueda y el motivo por el que el resultado es relevante para su consulta.

Por ejemplo, Gmail usa fragmentos para indicar la parte de un correo electrónico que coincide con la búsqueda:

Lista de fragmentos

Generar un fragmento de la base de datos tiene varios beneficios:

  1. Comodidad: No necesitas implementar lógica para generar fragmentos a partir de una búsqueda.
  2. Eficiencia: Los fragmentos reducen el tamaño de salida del servidor.

La SNIPPET función crea el fragmento. Muestra la parte pertinente del valor de cadena original junto con las posiciones de los caracteres para destacar. Luego, el cliente puede elegir cómo mostrar el fragmento al usuario final (por ejemplo, con texto destacado o en negrita).

Por ejemplo, en el siguiente ejemplo, se usa SNIPPET para recuperar texto de AlbumTitle:

GoogleSQL

SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")

PostgreSQL

En este ejemplo, se usa spanner.snippet.

SELECT albumid, spanner.snippet(albumtitle, 'Fast Car')
FROM albums
WHERE spanner.search(albumtitle_tokens, 'Fast Car')

¿Qué sigue?