Vista geral das consultas

Esta página descreve a função SEARCH e o modo de consulta melhorado, que são usados para executar consultas de pesquisa de texto completo em tabelas do Spanner.

Consultar um índice de pesquisa

O Spanner fornece a função SEARCH para usar em consultas de índice de pesquisa. Um exemplo de utilização seria uma aplicação em que os utilizadores introduzem texto numa caixa de pesquisa e a aplicação envia a entrada do utilizador diretamente para a função SEARCH. A função SEARCH usaria então um índice de pesquisa para encontrar esse texto.

A função SEARCH requer dois argumentos:

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

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

Não é possível usar a função SEARCH com consultas de transações.

A seguinte consulta usa a função SEARCH para devolver todos os álbuns que tenham 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 raw search query por predefinição. Podem ser especificadas sintaxes alternativas através do argumento SEARCH dialect.

dialeto rquery

O dialeto predefinido é a consulta de pesquisa não processada. O Spanner usa uma linguagem específica do domínio (DSL) denominada rquery.

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

Para obter informações sobre a utilização de rquery, consulte a sintaxe de rquery.

palavras dialeto

A palavra-chave dialect é semelhante a rquery, mas mais simples. 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 processadas como pontuações em vez de uma pesquisa de expressão e são ignoradas.

Com o dialeto de palavras, AND é aplicado implicitamente a todos os termos e é necessário durante a correspondência. Segue as mesmas regras que o tokenizador de texto simples ao dividir a consulta de pesquisa introduzida em termos.

Para informações sobre a utilização do dialeto words, consulte a sintaxe words.

words_phrase dialect

O dialeto words_phrase não usa operadores especiais e todos os termos são tratados como uma expressão, o que significa que os termos têm de estar adjacentes e na ordem especificada.

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

Para obter informações sobre a utilização do dialeto words_phrase, consulte a sintaxe words phrase.

Modo de consulta melhorado

O Spanner oferece dois modos de pesquisa de texto completo: uma pesquisa básica baseada em tokens e um modo mais avançado denominado enhance_query. Quando ativada, enhance_query expande a consulta de pesquisa para incluir termos relacionados e sinónimos, aumentando a probabilidade de encontrar resultados relevantes.

Para ativar esta opção, defina o argumento opcional enhance_query=>true na função SEARCH. Por exemplo, a consulta de pesquisa hotl cal corresponde ao álbum Hotel California.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'hotl cal', enhance_query=>true)

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'hotl cal', enhance_query=>true)

O modo enhance_query é uma opção de tempo de consulta. Não afeta a tokenização. Pode usar o mesmo índice de pesquisa com ou sem enhance_query.

A Google está continuamente a melhorar os algoritmos de melhoramento de consultas. Como resultado, uma consulta com enhance_query == true pode gerar resultados ligeiramente diferentes ao longo do tempo.

Quando o modo enhance_query está ativado, pode aumentar o número de termos que a função SEARCH procura, o que pode aumentar ligeiramente a latência.

Por exemplo, a seguinte consulta usa um limite de tempo de três segundos e falha se enhance_query não estiver disponível:

GoogleSQL

@{require_enhance_query=true, enhance_query_timeout_ms=3000}
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'fast car', enhance_query=>true)

PostgreSQL

/*@require_enhance_query=true, enhance_query_timeout_ms=3000*/
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fast car', enhance_query=>true)

Requisitos de consultas SQL

Existem várias condições que uma consulta SQL tem de cumprir para usar um índice de pesquisa. Se estas condições não forem cumpridas, a consulta usa um plano de consulta alternativo ou falha se não existir um plano alternativo.

As consultas têm de cumprir as seguintes condições:

  • A função SEARCH e as funções SEARCH_SUBSTRING requerem um índice de pesquisa. O Spanner não suporta estas funções em consultas na tabela base ou nos índices secundários.

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

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

  • Todas as colunas TOKENLIST referenciadas pelos operadores SEARCH e SEARCH_SUBSTRING têm de 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 seguinte consulta falha porque não existe 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 parâmetros de consulta $1 e $2 que estão associados a "carro rápido" e "nota azul", respetivamente.

    SELECT albumid
    FROM albums
    WHERE spanner.search(albumtitle_tokens, $1)
        AND spanner.search(albumstudio_tokens, $2)
    
  • Se a coluna de ordem de ordenação for anulável, o esquema e a consulta têm de excluir as linhas em que a coluna de ordem de ordenação é NULL. Para ver detalhes, consulte o artigo Ordem de ordenação do índice de pesquisa.

  • Se o índice de pesquisa for filtrado por NULL, a consulta tem de incluir a mesma expressão de filtragem por NULL usada num índice. Consulte os índices de pesquisa filtrados por NULL para ver detalhes.

  • Os índices de pesquisa e as funções de pesquisa não são suportados em DML, DML particionados nem consultas particionadas.

  • Os índices de pesquisa e as funções de pesquisa são normalmente usados em transações só de leitura. Se os requisitos da aplicação permitirem resultados desatualizados, pode 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 o artigo Leia dados desatualizados. Isto é particularmente útil para consultas de pesquisa que se expandem para 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/escrita. Durante a execução, as consultas de pesquisa bloqueiam uma partição de índice inteira. Consequentemente, uma taxa elevada de consultas de pesquisa em transações de leitura/escrita pode causar conflitos de bloqueio que originam picos de latência. Por predefinição, os índices de pesquisa não são selecionados automaticamente em transações de leitura/escrita. Se uma consulta for forçada a usar um índice de pesquisa numa transação de leitura/escrita, falha por predefinição. Também falha se a consulta contiver alguma das funções de pesquisa. Este comportamento pode ser substituído com a sugestão ao nível da declaração do GoogleSQL (mas as consultas continuam propensas a conflitos de bloqueio).@{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE}

Assim que as condições de elegibilidade do índice forem cumpridas, o otimizador de consultas tenta acelerar as condições de consulta não textuais (como Rating > 4). Se o índice de pesquisa não incluir a coluna TOKENLIST adequada, a condição não é acelerada e permanece 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 que use parâmetros de consulta para a pesquisa de texto completo em vez de literais de strings quando os argumentos permitem o valor do parâmetro de consulta.

Seleção de índice

Normalmente, o Spanner seleciona o índice mais eficiente para uma consulta através da modelagem baseada em custos. No entanto, a sugestão 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 elegível, a consulta falha, mesmo que existam outros índices de pesquisa elegíveis.

Fragmentos nos resultados da pesquisa

Um fragmento é um excerto de texto extraído de uma determinada string que dá aos utilizadores uma ideia do que um resultado da pesquisa contém e o motivo pelo qual o resultado é relevante para a respetiva consulta.

Por exemplo, o Gmail usa fragmentos para indicar a parte de um email que corresponde à consulta de pesquisa:

Lista de fragmentos

A geração de um fragmento pela base de dados tem várias vantagens:

  1. Comodidade: não precisa de implementar lógica para gerar fragmentos a partir de uma consulta de pesquisa.
  2. Eficiência: os fragmentos reduzem o tamanho da saída do servidor.

A função SNIPPET cria o fragmento. Devolve a parte relevante do valor da string original, juntamente com as posições dos carateres a realçar. O cliente pode, em seguida, escolher como apresentar o fragmento ao utilizador final (por exemplo, usando texto realçado ou em negrito).

Por exemplo, o seguinte usa SNIPPET para obter 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')

O que se segue?