Le applicazioni web spesso impaginano i dati quando vengono presentati agli utenti. L'utente finale riceve una pagina di risultati e, quando passa alla pagina successiva, viene recuperato e presentato il batch di risultati successivo. Questa pagina descrive come aggiungere la paginazione ai risultati di ricerca quando si esegue una ricerca full-text in Spanner.
Opzioni di paginazione
Esistono due modi per implementare le query impaginate in Spanner: la paginazione basata su chiave (consigliata) e la paginazione basata su offset.
La paginazione basata su chiave è un metodo per recuperare i risultati di ricerca in blocchi più piccoli e gestibili, garantendo al contempo risultati coerenti tra le richieste. Un identificatore univoco (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 chiave. Sebbene la paginazione basata su offset sia più facile da implementare, presenta due svantaggi significativi:
- Costo della query più elevato:la paginazione basata su offset recupera e scarta ripetutamente gli stessi risultati, con conseguente aumento dei costi e riduzione del rendimento.
- Risultati incoerenti: nelle query impaginate, ogni pagina viene in genere 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 tra le query, portando a risultati incoerenti tra le pagine.
La paginazione basata su chiave, d'altra parte, utilizza un identificatore univoco (chiave) dell'ultimo risultato di una pagina per recuperare il set di risultati successivo. Ciò garantisce 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 con lo stesso timestamp. Tuttavia, questa 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 è di 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 chiave
La paginazione basata su chiave ricorda l'ultimo elemento della pagina precedente e lo utilizza come punto di partenza per la query della pagina successiva. Per ottenere questo risultato, la query deve restituire le colonne specificate nella clausola ORDER BY e limitare il numero di righe utilizzando LIMIT.
Affinché la paginazione basata su chiave 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 tie-breaker, 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 è simile alla seguente:
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;
AlbumId è il tie-breaker perché ReleaseTimestamp non è una chiave. Potrebbero esistere 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 (ascendente o discendente), dei tie-breaker e dell'ordine dei valori NULL per le colonne nullable.
Nel nostro esempio, AlbumId è l'unica colonna chiave (in ordine crescente) e non può essere NULL, quindi la condizione è la seguente:
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
Questo esempio utilizza parametri di ricerca $1, $2, $3 e $4, che sono associati rispettivamente ai valori specificati per last_page_release_timestamp, last_page_album_id, query e page_size.
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;
Spanner interpreta questo tipo di condizione come ricercabile. Ciò significa che Spanner non legge l'indice dei documenti che stai filtrando. Questa ottimizzazione rende la paginazione basata su chiave molto più efficiente della paginazione basata su offset.
Utilizzare 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, sulla dimensione della pagina per la seconda pagina e sul doppio della dimensione della pagina per la terza pagina.
Ad esempio, la seguente query recupera la terza pagina, con una dimensione della pagina di 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;
Note sull'utilizzo:
- La clausola
ORDER BYè altamente consigliata per garantire un ordinamento coerente tra le pagine. - Nelle query di produzione, utilizza parametri di ricerca anziché le costanti per specificare
LIMITeOFFSETper rendere più efficiente la memorizzazione nella cache delle query. Per ulteriori informazioni, consulta Parametri di query.
Passaggi successivi
- Scopri come classificare i risultati di ricerca.
- Scopri come eseguire una ricerca di sottostringhe.
- Scopri come combinare query full-text e non testuali.
- Scopri come cercare in più colonne.