Expansão de consulta de pesquisa

Nesta página, descrevemos como usar o refinamento de consultas como parte de uma pesquisa de texto completo.

Para aumentar a probabilidade de encontrar resultados relevantes, o Spanner oferece recursos avançados que expandem a consulta de pesquisa para incluir termos relacionados, sinônimos e correções ortográficas. O Spanner oferece as seguintes opções para melhorar as consultas:

Consulta aprimorada

Para usar a consulta avançada, defina enhance_query=>true na função SEARCH. Em seguida, o Spanner expande automaticamente as consultas de pesquisa incluindo termos relacionados e sinônimos, aplicando a derivação e fazendo correções ortográficas. Por exemplo, ao usar a consulta avançada, 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)

enhance_query é uma opção de tempo de consulta que não afeta a tokenização. É possível usar o mesmo índice de pesquisa com ou sem enhance_query.

O Google está sempre aprimorando os algoritmos de refinamento de consultas. Como resultado, uma consulta com enhance_query => true pode gerar resultados ligeiramente diferentes ao longo do tempo.

Quando enhance_query é usado, a latência pode aumentar devido à sobrecarga de expandir a consulta de pesquisa e executar a consulta maior resultante.

Dicionários personalizados

É possível usar dicionários personalizados com a pesquisa de texto completo do Spanner para definir sinônimos de termos no seu conjunto de dados. Isso é útil para capturar sinônimos, acrônimos, termos equivalentes e outras variações de palavras para melhorar a recuperação dos resultados da pesquisa.

Criar uma tabela de dicionário personalizado

Um dicionário personalizado é uma tabela criada pelo usuário que contém pares de chave-valor de termos e sinônimos. Para criar um, inclua a opção fulltext_dictionary_table = true na instrução CREATE TABLE. A tabela precisa ter duas colunas:

  • Key: uma coluna de string não anulável para o termo a ser expandido com sinônimos.
  • Value: uma coluna de matriz de strings não anulável para uma matriz de sinônimos da chave.

Não pode haver outras colunas além de Key e Value na tabela. Se um termo de pesquisa corresponder a um Key no dicionário, a pesquisa será expandida para incluir todos os sinônimos correspondentes em Value, além do próprio termo principal. No exemplo a seguir, criamos uma tabela de dicionário personalizada chamada MyCustomDictionary. Você também precisa definir a opção de tabela fulltext_dictionary_table=true durante a criação.

GoogleSQL

CREATE TABLE MyCustomDictionary (
  Key STRING(MAX) NOT NULL,
  Value ARRAY<STRING(MAX)> NOT NULL,
) PRIMARY KEY(Key),
OPTIONS (fulltext_dictionary_table = true);

PostgreSQL

CREATE TABLE mycustomdictionary (
  key character varying  NOT NULL,
  value character varying [] NOT NULL,
  PRIMARY KEY(key)
)  WITH ( type = 'fulltext_dictionary')

Depois de criar a tabela, insira os sinônimos:

GoogleSQL

INSERT INTO MyCustomDictionary (Key, Value) VALUES
('album', ['vinyl', 'cassette']),
('edm', ['electronic dance music']);

PostgreSQL

INSERT INTO mycustomdictionary (key, value) VALUES
('album', ARRAY['vinyl', 'cassette']),
('edm', ARRAY['electronic dance music']);

Ao preencher a tabela, lembre-se do seguinte:

  • As chaves precisam ser palavras únicas.
  • Os valores podem ser palavras únicas ou frases. Se um valor tiver várias palavras, ele será tratado como uma pesquisa de frase durante a expansão de consulta.
  • Todas as chaves e valores precisam estar em letras minúsculas. Isso garante que eles correspondam aos tokens de pesquisa, que são convertidos em letras minúsculas pelo tokenizador padrão.

A expansão da pesquisa só ocorre quando um termo de pesquisa corresponde a um Key. Se um termo de pesquisa corresponder a um sinônimo em Value, mas não a um Key, a pesquisa não será expandida. Se você precisar de um mapeamento bidirecional (por exemplo, para que a pesquisa por vinyl ou cassette também encontre album), insira mapeamentos inversos na tabela de dicionário. O exemplo a seguir mostra como inserir mapeamentos bidirecionais para album, vinyl e cassette:

GoogleSQL

INSERT INTO MyCustomDictionary (Key, Value)
-- 1. Insert album -> vinyl, cassette
SELECT 'album', ['vinyl', 'cassette']
UNION ALL
-- 2. Insert vinyl -> album and cassette -> album
SELECT syn, ['album']
FROM UNNEST(['vinyl', 'cassette']) AS syn;

PostgreSQL

INSERT INTO mycustomdictionary (key, value)
-- 1. Insert album -> vinyl, cassette
SELECT 'album', ARRAY['vinyl', 'cassette']
UNION ALL
-- 2. Insert vinyl -> album and cassette -> album
SELECT syn, ARRAY['album']
FROM unnest(ARRAY['vinyl', 'cassette']) AS syn;

Usar um dicionário personalizado em consultas de pesquisa

Para usar um dicionário personalizado, especifique o nome da tabela de dicionário no argumento dictionary da função SEARCH.

  • Se um termo de pesquisa for uma chave no dicionário, SEARCH também vai procurar os valores dela. O termo album corresponde a mensagens que contêm vinyl ou cassette.

    GoogleSQL

    SELECT MessageId, Body
    FROM Messages
    WHERE SEARCH(Body_Tokens, 'album', dictionary=>'MyCustomDictionary');
    

    PostgreSQL

    SELECT messageid, body
    FROM messages
    WHERE spanner.search(body_tokens, 'album', dictionary=>'mycustomdictionary');
    
  • Quando um valor de dicionário contém várias palavras, como electronic dance music para a chave edm, ele é tratado como uma pesquisa de frase. Isso significa que os termos precisam aparecer adjacentes e na ordem exata especificada para serem considerados uma correspondência. Por exemplo, a consulta a seguir retorna resultados que contêm a frase exata "música eletrônica", mas não "música eletrônica de dança". Isso é útil principalmente para expandir acrônimos e pode ser usado da seguinte maneira:

    GoogleSQL

    SELECT MessageId, Body
    FROM Messages
    WHERE SEARCH(Body_Tokens, 'edm', dictionary=>'MyCustomDictionary');
    

    PostgreSQL

    SELECT messageid, body
    FROM messages
    WHERE spanner.search(body_tokens, 'edm', dictionary=>'mycustomdictionary');
    

Desatualização da pesquisa no dicionário

Por padrão, as entradas do dicionário personalizado são lidas com uma defasagem máxima de 15 segundos. Isso reduz a sobrecarga da operação de leitura, porque ler dados com alguma defasagem é mais eficiente do que ler os dados mais atuais. Por isso, as mudanças nas entradas do dicionário podem levar até 15 segundos para aparecer nas consultas de pesquisa. É possível substituir esse comportamento das seguintes maneiras:

  • Usando a opção de tabela fulltext_dictionary_staleness.
  • Usando a dica de consulta fulltext_dictionary_staleness para um controle mais granular.

A dica de consulta substitui a opção de tabela se ambas forem usadas.

Opção de tabela fulltext_dictionary_staleness

É possível definir a opção fulltext_dictionary_staleness para a tabela de dicionário. Todas as consultas que usam essa tabela de dicionário usam esse valor de defasagem, a menos que sejam substituídas pela dica de consulta.

GoogleSQL

O exemplo a seguir mostra como CREATE uma tabela com a opção fulltext_dictionary_staleness:

CREATE TABLE MyCustomDictionary (
  Key STRING(MAX) NOT NULL,
  Value ARRAY<STRING(MAX)> NOT NULL,
) PRIMARY KEY(Key),
OPTIONS (
  fulltext_dictionary_table = true,
  fulltext_dictionary_staleness = '5s'
);

O exemplo a seguir mostra como ALTER a tabela para mudar ou definir a opção fulltext_dictionary_staleness:

ALTER TABLE MyCustomDictionary SET OPTIONS (
  fulltext_dictionary_staleness = '60s'
);

PostgreSQL

O exemplo a seguir mostra como CREATE uma tabela com a opção fulltext_dictionary_staleness:

-- Create with 5s staleness
CREATE TABLE mycustomdictionary (
  key character varying NOT NULL,
  value character varying[]  NOT NULL,
  PRIMARY KEY(key)
) WITH (
  type = 'fulltext_dictionary',
  fulltext_dictionary_staleness = '5s'
);

A Interface PostgreSQL não é compatível com a tabela ALTER para mudar ou definir a opção fulltext_dictionary_staleness.

fulltext_dictionary_staleness dica de consulta

Para um controle mais granular, use a dica de consulta fulltext_dictionary_staleness para especificar uma defasagem diferente para uma consulta individual. Essa dica substitui a configuração no nível da tabela.

O exemplo a seguir usa uma dica para realizar pesquisas na tabela de dicionário com inatividade zero. Isso garante que as entradas de dicionário mais atuais sejam lidas. Essa abordagem pode aumentar a latência da consulta porque a leitura dos dados mais atuais é menos eficiente do que permitir alguma defasagem.

GoogleSQL

@{fulltext_dictionary_staleness="0s"}
SELECT MessageId, Body
FROM Messages
WHERE SEARCH(Body_Tokens, 'Bill', dictionary=>'MyCustomDictionary');

PostgreSQL

/*@ fulltext_dictionary_staleness='0s' */
SELECT messageid, body
FROM messages
WHERE spanner.search(body_tokens, 'Bill', dictionary=>'mycustomdictionary');

Limitações conhecidas com tabelas de dicionário personalizadas

  • O suporte para usar a importação e exportação do Spanner com tabelas de dicionário personalizadas é limitado.
  • As tabelas de dicionário personalizadas precisam ser criadas no esquema padrão e não podem ser criadas em esquemas nomeados.
  • As tabelas de dicionário personalizado são compatíveis apenas com o dialeto de consulta SEARCH padrão.

Como combinar dicionários personalizados com consultas aprimoradas

É possível combinar sinônimos do dicionário personalizado com enhanced query definindo dictionary e enhance_query=>true na função SEARCH. A melhoria de consultas pode expandir as consultas com sinônimos comuns ou correções ortográficas, enquanto os dicionários personalizados permitem definir suas próprias expansões. Por exemplo, se enhance_query expandir album para incluir record e MyCustomDictionary mapear album para ['vinyl', 'cassette'], a consulta a seguir vai corresponder a mensagens que contenham album, record, vinyl ou cassette:

GoogleSQL

SELECT MessageId, Body
FROM Messages
WHERE SEARCH(Body_Tokens, 'album', enhance_query=>true, dictionary=>'MyCustomDictionary');

PostgreSQL

SELECT messageid, body
FROM messages
WHERE spanner.search(body_tokens, 'album', enhance_query=>true, dictionary=>'mycustomdictionary');

Quando os dois recursos estão ativados, eles operam de forma independente nos termos de pesquisa originais, e os termos gerados por um recurso não são usados como entrada para o outro.

A seguir