Paginare i risultati di ricerca

Le applicazioni web spesso paginano i dati mentre vengono presentati agli utenti. L'utente finale riceve una pagina di risultati e, quando passa alla pagina successiva, viene recuperato e presentato il successivo lotto di risultati. Questa pagina descrive come aggiungere la paginazione ai risultati di ricerca quando esegui una ricerca a testo intero in Spanner.

Opzioni di paginazione

Esistono due modi per implementare le query paginate in Spanner: impaginazione basata su chiavi (consigliata) e impaginazione basata su offset.

La paginazione basata su chiavi è un metodo per recuperare i risultati di ricerca in blocchi più piccoli e gestibili, garantendo al contempo risultati coerenti tra le richieste. Un identificatore unico (la "chiave") dell'ultimo risultato di una pagina viene utilizzato come punto di riferimento per recuperare il set di risultati successivo.

In genere, Spanner consiglia di utilizzare la paginazione basata su chiavi. Sebbene la paginazione basata su offset sia più facile da implementare, presenta due svantaggi significativi:

  1. Costo delle query più elevato:la paginazione basata su offset recupera e ignora ripetutamente gli stessi risultati, con un conseguente aumento dei costi e una diminuzione delle prestazioni.
  2. Risultati incoerenti: nelle query con paginazione, in genere ogni pagina viene recuperata con un timestamp di lettura diverso. Ad esempio, la prima pagina potrebbe provenire da una query alle 13:00 e la successiva da una query alle 13:10. Ciò significa che i risultati di ricerca possono cambiare da una query all'altra, con risultati incoerenti tra le pagine.

La paginazione basata su chiavi, invece, utilizza un identificatore univoco (chiave) dell'ultimo risultato di una pagina per recuperare l'insieme di risultati successivo. In questo modo viene garantito sia un recupero efficiente sia risultati coerenti, anche se i dati sottostanti cambiano.

Per garantire la stabilità dei risultati della pagina, l'applicazione potrebbe emettere tutte le query per pagine diverse allo stesso timestamp. Tuttavia, l'operazione potrebbe non riuscire se la query supera il periodo di conservazione della versione (il valore predefinito è 1 ora). Ad esempio, questo errore si verifica se version_gc è equale a un'ora e l'utente finale ha recuperato i primi risultati alle 13:00 e ha fatto clic su Avanti alle 15:00.

Utilizzare la paginazione basata su chiavi

La paginazione basata su chiavi memorizza l'ultimo elemento della pagina precedente e lo utilizza come punto di partenza per la query della pagina successiva. Per farlo, la query deve restituire le colonne specificate nella clausola ORDER BY e limitare il numero di righe utilizzando LIMIT.

Affinché la paginazione basata su chiavi funzioni, la query deve ordinare i risultati in base a un ordine totale rigoroso. Il modo più semplice per ottenerne uno è scegliere un ordine totale e poi aggiungere le colonne di spareggio, se necessario. Nella maggior parte dei casi, l'ordine totale è l'ordine di ordinamento dell'indice di ricerca e la combinazione univoca di colonne è la chiave primaria della tabella di base.

Utilizzando il nostro schema di esempio Albums, per la prima pagina la query è la seguente:

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

AlbumId è il criterio di parità poiché ReleaseTimestamp non è una chiave. Potrebbero esserci due album diversi con lo stesso valore per ReleaseTimestamp.

Per riprendere, l'applicazione esegue di nuovo la stessa query, ma con una clausola WHERE che limita i risultati della pagina precedente. La condizione aggiuntiva deve tenere conto della direzione della chiave (crescente o decrescente), dei criteri di parità e dell'ordine dei valori NULL per le colonne con valori NULL.

Nel nostro esempio, AlbumId è l'unica colonna chiave (in ordine crescente) e non può essere NULL, quindi la condizione è la seguente:

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;

Spanner interpreta questo tipo di condizione come cercabile. Ciò significa che Spanner non legge l'indice dei documenti che stai escludendo. Questa ottimizzazione rende la paginazione basata su chiavi molto più efficiente rispetto alla paginazione basata su offset.

Utilizza la paginazione basata su offset

La paginazione basata su offset sfrutta le clausole LIMIT e OFFSET della query SQL per simulare le pagine. Il valore LIMIT indica il numero di risultati per pagina. Il valore OFFSET è impostato su zero per la prima pagina, sulle dimensioni della pagina per la seconda pagina e sul doppio delle dimensioni della pagina per la terza pagina.

Ad esempio, la seguente query recupera la terza pagina, con una dimensione di 50 pagine:

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

Note sull'utilizzo:

  • La clausola ORDER BY è vivamente consigliata per garantire un ordinamento coerente tra le pagine.
  • Nelle query di produzione, utilizza parametri di ricerca anziché le costanti per specificare LIMIT e OFFSET per rendere la memorizzazione nella cache delle query più efficiente. Per ulteriori informazioni, consulta la sezione Parametri di query.

Passaggi successivi