Paginar resultados da pesquisa

Os aplicativos da Web geralmente paginam os dados conforme são apresentados aos usuários. O usuário final recebe uma página de resultados e, quando ele navega para a próxima página, o próximo lote de resultados é recuperado e apresentado. Esta página descreve como adicionar paginação aos resultados da pesquisa ao realizar uma pesquisa de texto completo no Spanner.

Opções de paginação

Há duas maneiras de implementar consultas paginadas no Spanner: paginação baseada em chaves (recomendada) e paginação baseada em deslocamento.

A paginação baseada em chave é um método para recuperar resultados de pesquisa em partes menores e mais gerenciadas, garantindo resultados consistentes em todas as solicitações. Um identificador exclusivo (a "chave") do último resultado de uma página é usado como ponto de referência para buscar o próximo conjunto de resultados.

O Spanner geralmente recomenda usar a paginação baseada em chaves. Embora a paginação baseada em deslocamento seja mais fácil de implementar, ela tem duas desvantagens significativas:

  1. Custo de consulta mais alto:a paginação baseada em deslocamento recupera e descarta repetidamente os mesmos resultados, o que aumenta os custos e diminui a performance.
  2. Resultados inconsistentes:em consultas paginadas, cada página é normalmente recuperada em um carimbo de data/hora de leitura diferente. Por exemplo, a primeira página pode vir de uma consulta às 13h, e a próxima de uma consulta às 13h10. Isso significa que os resultados da pesquisa podem mudar entre as consultas, resultando em resultados inconsistentes nas páginas.

A paginação baseada em chave, por outro lado, usa um identificador exclusivo (chave) do último resultado de uma página para buscar o próximo conjunto de resultados. Isso garante a recuperação eficiente e resultados consistentes, mesmo que os dados subjacentes mudem.

Para oferecer estabilidade nos resultados da página, o aplicativo poderia emitir todas as consultas para páginas diferentes no mesmo carimbo de data/hora. No entanto, isso pode falhar se a consulta exceder o período de retenção da versão. O padrão é de 1 hora. Por exemplo, essa falha acontece se version_gc for uma hora e o usuário final tiver buscado os primeiros resultados às 13h e clicado em Próxima às 15h.

Usar a paginação baseada em chaves

A paginação baseada em chaves lembra o último item da página anterior e o usa como ponto de partida para a consulta da próxima página. Para isso, a consulta precisa retornar as colunas especificadas na cláusula ORDER BY e limitar o número de linhas usando LIMIT.

Para que a paginação baseada em chave funcione, a consulta precisa ordenar os resultados por uma ordem total rígida. A maneira mais fácil de conseguir uma é escolher qualquer ordem total e adicionar colunas de desempate, se necessário. Na maioria dos casos, a ordem total é a ordem de classificação do índice de pesquisa e a combinação exclusiva de colunas é a chave primária da tabela base.

Usando nosso esquema de amostra Albums, para a primeira página, a consulta é semelhante a esta:

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

O AlbumId é o desempate, já que ReleaseTimestamp não é uma chave. Talvez existam dois álbuns diferentes com o mesmo valor para ReleaseTimestamp.

Para retomar, o aplicativo executa a mesma consulta novamente, mas com uma cláusula WHERE que restringe os resultados da página anterior. A condição adicional precisa considerar a direção da chave (ascendente ou descendente), os desempates e a ordem dos valores NULL para colunas anuláveis.

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

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;

O Spanner interpreta esse tipo de condição como buscável. Isso significa que o Spanner não lê o índice dos documentos que você está filtrando. Essa otimização é o que torna a paginação baseada em chave muito mais eficiente do que a baseada em deslocamento.

Usar a paginação com base no deslocamento

A paginação baseada em deslocamento aproveita as 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 e o dobro do tamanho da página para a terceira.

Por exemplo, a consulta a seguir busca a terceira página, com um tamanho de página de 50:

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

Observações sobre o uso:

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

A seguir