Visão geral da consulta

Esta página descreve a função SEARCH e seus vários recursos avançados, que são usados para realizar consultas de pesquisa de texto completo em tabelas do Spanner.

Consultar um índice de pesquisa

O Spanner oferece a SEARCH função para consultas de índice de pesquisa. Um exemplo de caso de uso seria um aplicativo em que os usuários inserem texto em uma caixa de pesquisa e o aplicativo envia a entrada do usuário diretamente para a função SEARCH. A função SEARCH usaria um índice de pesquisa para encontrar esse texto.

A função SEARCH exige dois argumentos:

  • Um nome de índice de pesquisa
  • Uma consulta de pesquisa

A função SEARCH só funciona quando um índice de pesquisa é definido. A função SEARCH pode ser combinada com qualquer construção SQL arbitrária, como filtros, agregações ou mesclagens.

A função SEARCH não pode ser usada com consultas de transação.

A consulta a seguir usa a função SEARCH para retornar todos os álbuns que têm friday ou monday no título:

GoogleSQL

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

PostgreSQL

Este exemplo usa spanner.search.

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

Consulta de pesquisa

As consultas de pesquisa usam a sintaxe de consulta de pesquisa bruta por padrão. Sintaxes alternativas podem ser especificadas usando o SEARCH dialect argumento.

Dialeto rquery

O dialeto padrão é a consulta de pesquisa bruta. O Spanner usa uma linguagem específica do domínio (DSL, na sigla em inglês) chamada rquery.

A linguagem rquery segue as mesmas regras do tokenizador de texto simples ao dividir a consulta de pesquisa de entrada em termos distintos. Isso inclui a segmentação de idiomas asiáticos.

Para informações sobre como usar o rquery, consulte a sintaxe do rquery.

Dialeto words

O dialeto words é como o rquery, mas mais simples. Ele não usa operadores especiais. Por exemplo, OR é tratado como um termo de pesquisa em vez de um operador de disjunção. As aspas duplas são tratadas como pontuações em vez de uma pesquisa de frase e são ignoradas.

Com o dialeto words, AND é aplicado implicitamente a todos os termos e é obrigatório durante a correspondência. Ele segue as mesmas regras do tokenizador de texto simples ao dividir a consulta de pesquisa de entrada em termos.

Para informações sobre como usar o dialeto words, consulte a sintaxe words.

Dialeto words_phrase

O dialeto words_phrase não usa operadores especiais e todos os termos são tratados como uma frase, o que significa que os termos precisam ser adjacentes e na ordem especificada.

Assim como o rquery, o dialeto words_phrase segue as mesmas regras do tokenizador de texto simples ao dividir a consulta de pesquisa de entrada em termos.

Para informações sobre como usar o dialeto words_phrase, consulte a sintaxe da frase words.

Expandir consultas de pesquisa para aumentar os resultados relacionados

Você pode aumentar a probabilidade de encontrar resultados relevantes com os recursos avançados do Spanner para expandir consultas de pesquisa com termos relacionados, sinônimos e correções ortográficas. Esses recursos incluem:

Para mais informações, consulte Pesquisar com aprimoramento de consultas.

Requisitos de consulta SQL

Há várias condições que uma consulta SQL precisa atender para usar um índice de pesquisa. Se essas condições não forem atendidas, a consulta usará um plano de consulta alternativo ou falhará se não houver um plano alternativo.

As consultas precisam atender às seguintes condições:

  • As funções SEARCH e SEARCH_SUBSTRING exigem um índice de pesquisa. O Spanner não oferece suporte a essas funções em consultas na tabela de base ou em índices secundários.

  • Os índices particionados precisam ter todas as colunas de partição vinculadas por uma condição de igualdade na WHERE cláusula da consulta.

    Por exemplo, se um índice de pesquisa for definido como PARTITION BY x, y, a consulta precisará ter uma conjunção na cláusula WHERE de x = <parameter or constant> AND y = <parameter or constant>. Esse índice de pesquisa não será considerado pelo otimizador de consultas se essa condição estiver ausente.

  • Todas as colunas TOKENLIST referenciadas pelos operadores SEARCH e SEARCH_SUBSTRING precisam ser indexadas no mesmo índice de pesquisa.

    Por exemplo, considere a seguinte tabela e definição de í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);
    

    A consulta a seguir falha porque não há um único índice de pesquisa que indexe AlbumTitle_Tokens e AlbumStudio_Tokens:

    GoogleSQL

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

    PostgreSQL

    Este exemplo usa os parâmetros de consulta $1 e $2, que estão vinculados a "fast car" e "blue note", respectivamente.

    SELECT albumid
    FROM albums
    WHERE spanner.search(albumtitle_tokens, $1)
        AND spanner.search(albumstudio_tokens, $2)
    
  • Se a coluna de ordem de classificação for anulável, o esquema e a consulta precisarão excluir linhas em que a coluna de ordem de classificação seja NULL. Para mais detalhes, consulte Ordem de classificação do índice da Pesquisa.

  • Se o índice de pesquisa for filtrado por NULL, a consulta precisará incluir a mesma expressão de filtragem de NULL usada em um índice. Consulte Índices de pesquisa filtrados por NULL para mais detalhes.

  • Os índices de pesquisa e as funções de pesquisa não são compatíveis com DML, DML particionada ou consultas particionadas.

  • Os índices de pesquisa e as funções de pesquisa são normalmente usados em transações somente leitura. Se os requisitos do aplicativo permitirem resultados desatualizados, talvez seja possível melhorar a latência executando consultas de pesquisa com uma duração de desatualização de 10 segundos ou mais. Para mais informações, consulte Ler dados desatualizados. Isso é especialmente útil para consultas de pesquisa que se espalham por muitas divisões de índice.

Os índices de pesquisa e as funções de pesquisa não são recomendados em transações de leitura/gravação. Durante a execução, as consultas de pesquisa bloqueiam uma partição de índice inteira. Como resultado, uma alta taxa de consultas de pesquisa em transações de leitura/gravação pode causar conflitos de bloqueio que levam a picos de latência. Por padrão, os índices de pesquisa não são selecionados automaticamente em transações de leitura/gravação. Se uma consulta for forçada a usar um índice de pesquisa em uma transação de leitura/gravação, ela falhará por padrão. Ela também falhará se a consulta contiver alguma das funções de pesquisa. Esse comportamento pode ser substituído pela dica no nível da instrução @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} do GoogleSQL, mas as consultas ainda estão sujeitas a conflitos de bloqueio.

Depois que as condições de qualificação do índice forem atendidas, o otimizador de consultas tentará acelerar as condições de consulta não textuais (como Rating > 4). Se o índice de pesquisa não incluir a coluna TOKENLIST apropriada, a condição não será acelerada e permanecerá uma condição residual.

Parâmetros de consulta

Os argumentos de consulta de pesquisa são especificados como um literal ou um parâmetro de consulta. Recomendamos o uso de parâmetros de consulta para pesquisa de texto completo em vez de literais de string quando os argumentos permitirem o valor do parâmetro de consulta.

Seleção de índice

O Spanner normalmente seleciona o índice mais eficiente para uma consulta usando a modelagem baseada em custos. No entanto, a dica FORCE_INDEX instrui explicitamente o Spanner a usar um índice de pesquisa específico. Por exemplo, o seguinte mostra como forçar o Spanner a usar o 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')

Se o índice de pesquisa especificado não for qualificado, a consulta falhará, mesmo que haja outros índices de pesquisa qualificados.

Snippets nos resultados da pesquisa

Um snippet é um trecho de texto extraído de uma determinada string que dá aos usuários uma ideia do que um resultado de pesquisa contém e o motivo pelo qual o resultado é relevante para a consulta.

Por exemplo, o Gmail usa snippets para indicar a parte de um e-mail que corresponde à consulta de pesquisa:

Lista de snippets

Gerar um snippet no banco de dados tem vários benefícios:

  1. Conveniência: não é necessário implementar a lógica para gerar snippets de uma consulta de pesquisa.
  2. Eficiência: os snippets reduzem o tamanho da saída do servidor.

A SNIPPET função cria o snippet. Ela retorna a parte relevante do valor da string original, juntamente com as posições dos caracteres a serem destacados. O cliente pode escolher como mostrar o snippet ao usuário final (por exemplo, usando texto destacado ou em negrito).

Por exemplo, o seguinte usa SNIPPET para recuperar texto de AlbumTitle:

GoogleSQL

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

PostgreSQL

Este exemplo usa spanner.snippet.

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

A seguir