Encontrar correspondências aproximadas com a pesquisa aproximada

Esta página descreve como usar uma pesquisa aproximada como parte de uma pesquisa de texto completo.

Além de realizar pesquisas de token exatas usando as funções SEARCH e SEARCH_SUBSTRING, o Spanner também oferece suporte a pesquisas aproximadas (ou vagas). As pesquisas aproximadas encontram documentos correspondentes, apesar de pequenas diferenças entre a consulta e o documento.

O Spanner oferece suporte aos seguintes tipos de pesquisa aproximada:

  • Pesquisa aproximada com base em n-gramas
  • Pesquisa fonética usando Soundex

A pesquisa fuzzy baseada em n-gramas depende da mesma tokenização de substring que uma pesquisa de substring precisa. A configuração do tokenizer é importante porque afeta a qualidade e o desempenho da pesquisa. O exemplo a seguir mostra como criar uma consulta com palavras com erros de ortografia ou com grafia diferente para encontrar correspondências aproximadas no índice de pesquisa.

Esquema

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (
    TOKENIZE_SUBSTRING(AlbumTitle, ngram_size_min=>2, ngram_size_max=>3,
                       relative_search_types=>["word_prefix", "word_suffix"])) HIDDEN
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING (AlbumTitle);

Consulta

A consulta a seguir encontra os álbuns com títulos mais próximos de "Hatel Kaliphorn", como "Hotel California".

SELECT AlbumId
FROM Albums
WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn")
ORDER BY SCORE_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn") DESC
LIMIT 10

Otimizar a performance e a recuperação de uma pesquisa aproximada baseada em n-gramas

A consulta de exemplo na seção anterior faz pesquisas em duas fases, usando duas funções diferentes:

  1. SEARCH_NGRAMS encontra todos os álbuns candidatos que têm n-gramas compartilhados com a consulta de pesquisa. Por exemplo, os n-gramas de três caracteres para "California" incluem [cal, ali, lif, ifo, for, orn, rni, nia] e para "Kaliphorn" incluem [kal, ali, lip, iph, pho, hor, orn]. Os n-gramas compartilhados nesses conjuntos de dados são [ali, orn]. Por padrão, SEARCH_NGRAMS corresponde a todos os documentos com pelo menos dois n-gramas compartilhados. Portanto, "Kaliphorn" corresponde a "California".
  2. SCORE_NGRAMS classifica as correspondências por semelhança. A semelhança de duas strings é definida como uma proporção de n-gramas compartilhados distintos para n-gramas distintos não compartilhados:
shared_ngramstotal_ngramsindex+total_ngramsqueryshared_ngrams

Normalmente, a pesquisa_query é a mesma nas funções SEARCH_NGRAMS e SCORE_NGRAMS. A maneira recomendada de fazer isso é usar o argumento com parâmetros de consulta em vez de literal de string e especificar o mesmo parâmetro de consulta nas funções SEARCH_NGRAMS e SCORE_NGRAMS.

O Spanner tem três argumentos de configuração que podem ser usados com SEARCH_NGRAMS:

  1. O tamanho mínimo e máximo de n-gramas especificados em TOKENIZE_SUBSTRING ou TOKENIZE_NGRAMS. Não recomendamos n-gramas de um caractere porque eles correspondem a um número muito grande de documentos. Por outro lado, n-gramas longos fazem com que SEARCH_NGRAMS ignore palavras curtas com erros ortográficos.
  2. Número mínimo de n-gramas que SEARCH_NGRAMS precisa corresponder (definido com os argumentos min_ngrams e min_ngrams_percent em SEARCH_NGRAMS). Números maiores geralmente tornam a consulta mais rápida, mas reduzem o recall.

Para alcançar um bom equilíbrio entre desempenho e recuperação, esses argumentos podem ser configurados para se ajustar à consulta e à carga de trabalho específicas.

Também recomendamos incluir um LIMIT interno para evitar a criação de consultas muito caras quando uma combinação de n-gramas populares é encontrada:

SELECT AlbumId
FROM (
  SELECT AlbumId,
         SCORE_NGRAMS(AlbumTitle_Tokens, @p) AS score
  FROM Albums
  WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, @p)
  LIMIT 10000  # inner limit
)
ORDER BY score DESC
LIMIT 10  # outer limit

Pesquisa aproximada com base em N-gramas versus modo de consulta aprimorado

Além da pesquisa aproximada baseada em n-gramas, o modo de consulta aprimorado também processa algumas palavras com erros ortográficos. Portanto, há uma coincidência entre os dois recursos. A tabela a seguir resume as diferenças:

Pesquisa imprecisa com base em n-gramas Modo de consulta aprimorado
Custo Requer uma tokenização de substring mais cara com base em n-grams Requer uma tokenização de texto completo mais barata
Tipos de consulta de pesquisa Funciona bem com documentos curtos com poucas palavras, como com o nome de uma pessoa, cidade ou produto Funciona igualmente bem com documentos e consultas de pesquisa de qualquer tamanho
Pesquisa de palavras parciais Realiza uma pesquisa de substring que permite erros ortográficos Suporte apenas a uma pesquisa de palavras inteiras (SEARCH_SUBSTRING não oferece suporte ao argumento enhance_query)
Palavras com erros de ortografia Suporta palavras com erros de ortografia no índice ou na consulta Suporte apenas para palavras com erros ortográficos na consulta
Correções Encontra correspondências com erros ortográficos, mesmo que não sejam palavras reais Corrige erros ortográficos de palavras comuns e conhecidas

Realizar uma pesquisa fonética com o Soundex

O Spanner fornece a função SOUNDEX para encontrar palavras com grafias diferentes, mas com a mesma pronúncia. Por exemplo, SOUNDEX("steven"), SOUNDEX("stephen") e SOUNDEX("stefan") são todos "s315", enquanto SOUNDEX("stella") é "s340". SOUNDEX diferencia maiúsculas de minúsculas e só funciona para alfabetos baseados em latim.

A pesquisa fonética com SOUNDEX pode ser implementada com uma coluna gerada e um índice de pesquisa, conforme mostrado no exemplo a seguir:

CREATE TABLE Singers (
  SingerId INT64,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
  Name STRING(MAX),
  NameSoundex STRING(MAX) AS (LOWER(SOUNDEX(Name))),
  NameSoundex_Tokens TOKENLIST AS (TOKEN(NameSoundex)) HIDDEN
) PRIMARY KEY(SingerId);

CREATE SEARCH INDEX SingersPhoneticIndex ON Singers(AlbumTitle_Tokens, NameSoundex_Tokens);

A consulta a seguir corresponde a "stefan" com "Steven" em SOUNDEX, com AlbumTitle contendo "cat":

SELECT SingerId
FROM Singers
WHERE NameSoundex = LOWER(SOUNDEX("stefan")) AND SEARCH(AlbumTitle_Tokens, "cat")

A seguir