Nesta página, descrevemos como classificar os resultados de pesquisas de texto completo no Spanner.
O Spanner oferece suporte ao cálculo de uma pontuação de topicalidade, que fornece um elemento básico para a criação de funções de classificação sofisticadas. Essas pontuações calculam a relevância de um resultado para uma consulta com base na frequência do termo de consulta e em outras opções personalizáveis.
O exemplo a seguir mostra como realizar uma pesquisa classificada usando a
SCORE
função:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY SCORE(AlbumTitle_Tokens, "fifth symphony") DESC
PostgreSQL
Este exemplo usa spanner.search
com
spanner.score.
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY spanner.score(albumtitle_tokens, 'fifth symphony') DESC
Pontuar termos de consulta com a função SCORE
A SCORE
função calcula uma pontuação para cada termo de consulta e combina as pontuações. A
pontuação por termo é baseada na frequência do termo – frequência inversa do documento
(TF/IDF, na sigla em inglês). A pontuação é um componente da ordenação final de um registro. A consulta a combina com outros indicadores, como a atualização que modula a pontuação de topicalidade.
Na implementação atual, a parte IDF do TF/IDF só está disponível quando
enhance_query=>true é usada. Ela calcula a frequência relativa das palavras com base no corpus da Web completo usado pela Pesquisa Google, em vez de um índice de pesquisa específico. Se a melhoria da consulta não estiver ativada, a pontuação só usará o componente de frequência do termo (TF), ou seja, o termo IDF será definido como 1.
A função SCORE retorna valores que servem como pontuações de relevância que o Spanner usa para estabelecer uma ordem de classificação. Eles não têm significado independente. Quanto maior a pontuação, melhor a correspondência com a consulta.
Geralmente, argumentos como query e enhance_query são os mesmos nas funções
SEARCH e SCORE para garantir a consistência na recuperação e na classificação.
A maneira recomendada de fazer isso é usar esses argumentos com
parâmetros de consulta
em vez de literais de string e especificar os mesmos parâmetros de consulta nas funções
SEARCH e SCORE.
Pontuar várias colunas
O Spanner usa a função SCORE para pontuar cada campo individualmente. A consulta combina essas pontuações individuais. Uma maneira comum de fazer isso é somar as pontuações individuais e, em seguida, aumentá-las de acordo com as ponderações de campo fornecidas pelo usuário (que são fornecidas usando parâmetros de consulta SQL).
Por exemplo, a consulta a seguir combina a saída de duas funções SCORE:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) OR SEARCH(Studio_Tokens, @p2)
ORDER BY SCORE(Title_Tokens, @p1) * @titleweight + SCORE(Studio_Tokens, @p2) * @studioweight
LIMIT 25
PostgreSQL
Este exemplo usa os parâmetros de consulta $1 e $2, que estão vinculados a "quinta sinfonia" e "blue note", respectivamente.
SELECT albumid
FROM albums
WHERE spanner.search(title_tokens, $1) OR spanner.search(studio_tokens, $2)
ORDER BY spanner.score(title_tokens, $1) * $titleweight
+ spanner.score(studio_tokens, $2) * $studioweight
LIMIT 25
O exemplo a seguir adiciona dois parâmetros de otimização:
- A atualização (
FreshnessBoost) aumenta a pontuação com(1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30) - A popularidade(
PopularityBoost) aumenta a pontuação multiplicando-a pelo fator(1 + IF(HasGrammy, @grammyweight, 0).
Para facilitar a leitura, a consulta usa o operador WITH.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) OR SEARCH(Studio_Tokens, @p2)
ORDER BY WITH(
TitleScore AS SCORE(Title_Tokens, @p1) * @titleweight,
StudioScore AS SCORE(Studio_Tokens, @p2) * @studioweight,
DaysOld AS (UNIX_MICROS(CURRENT_TIMESTAMP()) - ReleaseTimestamp) / 8.64e+10,
FreshnessBoost AS (1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30),
PopularityBoost AS (1 + IF(HasGrammy, @grammyweight, 0)),
(TitleScore + StudioScore) * FreshnessBoost * PopularityBoost)
LIMIT 25
PostgreSQL
Este exemplo usa os parâmetros de consulta $1, $2, $3, $4, $5 e $6, que estão vinculados aos valores especificados para titlequery, studioquery, titleweight, studioweight, grammyweight e freshnessweight, respectivamente.
SELECT albumid
FROM
(
SELECT
albumid,
spanner.score(title_tokens, $1) * $3 AS titlescore,
spanner.score(studio_tokens, $2) * $4 AS studioscore,
(extract(epoch FROM current_timestamp) * 10e+6 - releasetimestamp) / 8.64e+10 AS daysold,
(1 + CASE WHEN hasgrammy THEN $5 ELSE 0 END) AS popularityboost
FROM albums
WHERE spanner.search(title_tokens, $1) OR spanner.search(studio_tokens, $2)
) AS subquery
ORDER BY (subquery.TitleScore + subquery.studioscore)
* (1 + $6 * greatest(0, 30 - subquery.daysold) / 30) * subquery.popularityboost
LIMIT 25
TOKENLIST_CONCAT
também pode ser usado na pesquisa e na pontuação para simplificar as consultas quando apropriado.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
ORDER BY SCORE(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
LIMIT 25
PostgreSQL
Este exemplo usa
spanner.tokenlist_concat.
O parâmetro de consulta $1 está vinculado a "blue note".
SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[title_tokens, studio_tokens]), $1)
ORDER BY spanner.score(spanner.tokenlist_concat(ARRAY[title_tokens, studio_tokens]), $1)
LIMIT 25
Otimizar correspondências de ordem de consulta
O Spanner aplica uma otimização multiplicativa à saída da função SCORE para valores que contêm os termos de consulta na mesma ordem em que aparecem na consulta. Há duas versões dessa otimização: correspondência parcial e correspondência exata. Uma otimização de correspondência parcial é aplicada quando:
- O
TOKENLISTcontém todos os termos originais na consulta. - Os tokens são adjacentes uns aos outros e na mesma ordem em que aparecem na consulta.
Há algumas regras especiais para conjunções, negações e frases:
- Uma consulta com uma negação não pode receber uma otimização de correspondência parcial.
- Uma consulta com uma conjunção recebe uma otimização se parte da conjunção aparecer nos locais apropriados.
- Uma consulta com uma frase recebe uma otimização se a frase aparecer no
TOKENLIST, e o termo à esquerda da frase na consulta aparecer à esquerda da frase noTOKENLIST, e o mesmo se aplica ao termo à direita da frase.
O Spanner aplica uma otimização de correspondência exata quando todas as regras anteriores são verdadeiras e os primeiros e últimos tokens na consulta são os primeiros e últimos tokens no documento.
Exemplo de documento: Bridge Over Troubled Water
| Consulta | Otimização aplicada |
|---|---|
| Bridge Troubled | sem otimização |
| Bridge Over - other water | sem otimização |
| Bridge (Over OR Troubled) Water | sem otimização |
| Bridge Over | otimização parcial |
| Bridge Over (Troubled OR Water) | otimização parcial |
| Bridge Over Troubled Water | otimização exata |
| Bridge "Over Troubled" Water | otimização exata |
| Bridge ("Over Troubled" OR missingterm) Water | otimização exata |
Versões do marcador
O algoritmo do marcador é atualizado periodicamente. Cada versão agrupa um conjunto de melhorias no algoritmo de pontuação. Para uma lista detalhada das diferenças entre as versões, consulte Versões do marcador.
É possível definir a versão padrão do marcador para seu banco de dados ou especificar uma versão para uma consulta específica.
Definir a versão padrão do marcador do banco de dados
É possível definir a versão padrão do algoritmo do marcador para seu banco de dados. Essa opção determina qual versão do algoritmo de pontuação o Spanner usa quando a função SCORE é chamada sem uma opção de pontuação version explícita.
GoogleSQL
Defina a opção de banco de dados score_version:
ALTER DATABASE database_name SET OPTIONS (score_version = 2)
PostgreSQL
Defina a opção de banco de dados spanner.score_version:
ALTER DATABASE database_name SET "spanner.score_version" = 2
Os valores válidos para a opção de banco de dados são 1 ou 2. Se o parâmetro version estiver presente em uma solicitação, ele vai substituir a versão padrão do banco de dados.
Substituir a versão do marcador por consulta
É possível substituir a versão padrão do marcador para uma consulta específica usando o parâmetro version no argumento options da função SCORE. Se uma consulta definir uma versão do marcador, ela vai substituir a versão padrão do banco de dados.
O exemplo a seguir substitui a versão padrão do marcador especificando version no parâmetro options:
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, @query)
ORDER BY SCORE(
AlbumTitle_Tokens,
@query,
options=>JSON '{"version": 2}'
) DESC
PostgreSQL
Este exemplo usa o parâmetro de consulta $1, que está vinculado à string de consulta.
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, $1)
ORDER BY spanner.score(
albumtitle_tokens,
$1,
options => '{"version": 2}'::jsonb
) DESC
Limitar a profundidade de recuperação
Os índices de pesquisa geralmente contêm milhões de documentos. Para consultas em que os predicados têm baixa seletividade, não é prático classificar todos os resultados. As consultas de pontuação geralmente têm dois limites:
- Limite de profundidade de recuperação: o número máximo de linhas a serem pontuadas.
- Limite de tamanho do conjunto de resultados: o número máximo de linhas que a consulta deve retornar (normalmente o tamanho da página).
As consultas podem limitar a profundidade de recuperação com subconsultas SQL:
GoogleSQL
SELECT AlbumId
FROM
(
SELECT AlbumId, SCORE(Title_Tokens, @p1) AS score
FROM Albums
WHERE SEARCH(Title_Tokens, @p1)
ORDER BY ReleaseTimestamp DESC
LIMIT @retrieval_limit
)
ORDER BY score DESC
LIMIT @page_size
PostgreSQL
Este exemplo usa os parâmetros de consulta $1, $2 e $3, que estão vinculados aos valores especificados para title_query, retrieval_limit e page_size, respectivamente.
SELECT albumid
FROM
(
SELECT albumid, spanner.score(title_tokens, $1) AS score
FROM albums
WHERE spanner.search(title_tokens, $1)
ORDER BY releasetimestamp DESC
LIMIT $2
) AS subquery
ORDER BY score DESC
LIMIT $3
Isso funciona muito bem se o Spanner usar o indicador de classificação mais importante para classificar o índice.
A seguir
- Saiba mais sobre consultas de pesquisa de texto completo.
- Saiba como realizar uma pesquisa de substrings.
- Saiba como paginar os resultados da pesquisa.
- Saiba como misturar consultas de texto completo e não textuais.
- Saiba como pesquisar várias colunas.