Paginar resultados da pesquisa

As aplicações Web paginam frequentemente os dados à medida que são apresentados aos utilizadores. O utilizador final recebe uma página de resultados e, quando navega para a página seguinte, o lote de resultados seguinte é obtido e apresentado. Esta página descreve como adicionar a paginação aos resultados da pesquisa quando efetua uma pesquisa de texto completo no Spanner.

Opções de paginação

Existem duas formas de implementar consultas paginadas no Spanner: paginação baseada em chaves (recomendada) e paginação baseada em deslocamentos.

A paginação baseada em chaves é um método para obter resultados da pesquisa em blocos mais pequenos e mais fáceis de gerir, garantindo resultados consistentes em todos os pedidos. Um identificador exclusivo (a "chave") do último resultado de uma página é usado como ponto de referência para obter o conjunto seguinte de resultados.

Geralmente, o Spanner recomenda a utilização da paginação baseada em chaves. Embora a paginação baseada em deslocamentos seja mais fácil de implementar, tem duas desvantagens significativas:

  1. Custo de consulta mais elevado:a paginação baseada em deslocamentos obtém e descarta repetidamente os mesmos resultados, o que leva a um aumento dos custos e a uma diminuição do desempenho.
  2. Resultados inconsistentes: nas consultas paginadas, cada página é normalmente obtida com uma data/hora de leitura diferente. Por exemplo, a primeira página pode ser proveniente de uma consulta às 13:00 e a seguinte de uma consulta às 13:10. Isto significa que os resultados da pesquisa podem mudar entre consultas, o que leva a resultados inconsistentes nas páginas.

Por outro lado, a paginação baseada em chaves usa um identificador único (chave) do último resultado de uma página para obter o conjunto de resultados seguinte. Isto garante uma obtenção eficiente e resultados consistentes, mesmo que os dados subjacentes mudem.

Para oferecer estabilidade nos resultados das páginas, a aplicação pode emitir todas as consultas para diferentes páginas na mesma data/hora. No entanto, isto pode falhar se a consulta exceder o período de retenção de versões (o predefinido é 1 hora). Por exemplo, esta falha ocorre se version_gc for de uma hora e o utilizador final tiver obtido os primeiros resultados às 13:00 e clicado em Seguinte às 15:00.

Use a paginação baseada em chaves

A paginação baseada em chaves memoriza o último item da página anterior e usa-o como ponto de partida para a consulta da página seguinte. Para o conseguir, a consulta tem de devolver as colunas especificadas na cláusula ORDER BY e limitar o número de linhas através de LIMIT.

Para que a paginação baseada em chaves funcione, a consulta tem de ordenar os resultados por alguma ordem total rigorosa. A forma mais fácil de obter um é escolher qualquer total de pedidos e, em seguida, adicionar colunas de desempate, se necessário. Na maioria dos casos, a ordem total é a ordem de ordenação do índice de pesquisa e a combinação única de colunas é a chave principal da tabela base.

Usando o nosso esquema de exemplo Albums, para a primeira página, a consulta tem o seguinte aspeto:

GoogleSQL

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;

PostgreSQL

SELECT albumid, releasetimestamp
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 10;

O AlbumId é o fator de desempate, uma vez que ReleaseTimestamp não é uma chave. Podem existir dois álbuns diferentes com o mesmo valor para ReleaseTimestamp.

Para retomar, a aplicação executa novamente a mesma consulta, mas com uma cláusula WHERE que restringe os resultados da página anterior. A condição adicional tem de ter em conta a direção da chave (ascendente versus descendente), os critérios de desempate e a ordem dos valores NULL para colunas anuláveis.

No nosso exemplo, AlbumId é a única coluna de chave (por ordem crescente) e não pode ser NULL, pelo que a condição é a seguinte:

GoogleSQL

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
    OR (ReleaseTimestamp = @last_page_release_timestamp
        AND AlbumId > @last_page_album_id))
    AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;

PostgreSQL

Este exemplo usa os parâmetros de consulta $1, $2, $3 e $4, que estão associados aos valores especificados para last_page_release_timestamp, last_page_album_id, query e page_size, respetivamente.

SELECT albumid, releasetimestamp
FROM albums
WHERE (releasetimestamp < $1
    OR (releasetimestamp = $1
        AND albumid > $2))
    AND spanner.search(albumtitle_tokens, $3)
ORDER BY releasetimestamp DESC, albumid ASC
LIMIT $4;

O Spanner interpreta este tipo de condição como seekable. Isto significa que o Spanner não lê o índice dos documentos que está a filtrar. Esta otimização torna a paginação baseada em chaves muito mais eficiente do que a paginação baseada em deslocamentos.

Use paginação baseada em deslocamento

A paginação baseada em deslocamento tira partido das cláusulas LIMIT e OFFSET da consulta SQL para simular páginas. O valor LIMIT indica o número de resultados por página. O valor OFFSET é definido como zero para a primeira página, o tamanho da página para a segunda página e o dobro do tamanho da página para a terceira página.

Por exemplo, a seguinte consulta obtém a terceira página, com um tamanho da página de 50:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 50 OFFSET 100;

Notas de utilização:

  • A cláusula ORDER BY é altamente recomendada para garantir uma ordenação consistente entre as páginas.
  • Nas consultas de produção, use parâmetros de consulta em vez de constantes para especificar LIMIT e OFFSET para tornar o armazenamento em cache de consultas mais eficiente. Para mais informações, consulte Parâmetros de consulta.

O que se segue?