Webanwendungen paginieren Daten häufig, wenn sie Nutzern präsentiert werden. Der Endnutzer erhält eine Seite mit Ergebnissen. Wenn er zur nächsten Seite wechselt, wird der nächste Batch mit Ergebnissen abgerufen und präsentiert. Auf dieser Seite wird beschrieben, wie Sie Suchergebnissen eine Paginierung hinzufügen, wenn Sie eine Volltextsuche in Spanner durchführen.
Paginierungsoptionen
Es gibt zwei Möglichkeiten, paginierte Abfragen in Spanner zu implementieren: schlüsselbasierte Paginierung (empfohlen) und offsetbasierte Paginierung.
Die schlüsselbasierte Paginierung ist eine Methode zum Abrufen von Suchergebnissen in kleineren, besser verwaltbaren Blöcken, die für konsistente Ergebnisse bei allen Anfragen sorgt. Eine eindeutige ID (der „Schlüssel“) aus dem letzten Ergebnis einer Seite wird als Referenzpunkt verwendet, um die nächste Gruppe von Ergebnissen abzurufen.
Spanner empfiehlt im Allgemeinen die Verwendung der schlüsselbasierten Paginierung. Die offsetbasierte Paginierung ist zwar einfacher zu implementieren, hat aber zwei erhebliche Nachteile:
- Höhere Abfragekosten:Bei der offsetbasierten Paginierung werden dieselben Ergebnisse wiederholt abgerufen und verworfen, was zu höheren Kosten und einer geringeren Leistung führt.
- Inkonsistente Ergebnisse:Bei paginierten Abfragen wird jede Seite in der Regel mit einem anderen Lesestempel abgerufen. Die erste Seite kann beispielsweise aus einer Abfrage um 13:00 Uhr stammen und die nächste aus einer Abfrage um 13:10 Uhr. Das bedeutet, dass sich die Suchergebnisse zwischen den Abfragen ändern können, was zu inkonsistenten Ergebnissen auf den Seiten führt.
Bei der schlüsselbasierten Paginierung wird dagegen eine eindeutige ID (Schlüssel) aus dem letzten Ergebnis einer Seite verwendet, um die nächste Gruppe von Ergebnissen abzurufen. So werden sowohl ein effizienter Abruf als auch konsistente Ergebnisse gewährleistet, auch wenn sich die zugrunde liegenden Daten ändern.
Um die Stabilität der Seitenergebnisse zu gewährleisten, könnte die Anwendung alle Abfragen für verschiedene Seiten mit demselben Zeitstempel ausführen. Dies kann jedoch fehlschlagen, wenn die
Abfrage den Aufbewahrungszeitraum für Versionen
überschreitet
(Standard ist 1 Stunde). Dieser Fehler tritt beispielsweise auf, wenn version_gc eine Stunde beträgt und der Endnutzer die ersten Ergebnisse um 13:00 Uhr abgerufen und um 15:00 Uhr auf Weiter geklickt hat.
Schlüsselbasierte Paginierung verwenden
Bei der schlüsselbasierten Paginierung wird das letzte Element der vorherigen Seite gespeichert und als Ausgangspunkt für die Abfrage der nächsten Seite verwendet. Dazu muss die Abfrage die in der ORDER BY-Klausel angegebenen Spalten zurückgeben und die Anzahl der Zeilen mit LIMIT begrenzen.
Damit die schlüsselbasierte Paginierung funktioniert, müssen die Ergebnisse in der Abfrage nach einer strengen Gesamtordnung sortiert werden. Die einfachste Möglichkeit, eine solche Ordnung zu erhalten, besteht darin, eine beliebige Gesamt ordnung auszuwählen und bei Bedarf Spalten für die Auflösung von Unentschieden hinzuzufügen. In den meisten Fällen ist die Gesamtordnung die Sortierreihenfolge des Suchindex und die eindeutige Kombination von Spalten der Primärschlüssel der Basistabelle.
Bei Verwendung unseres Albums-Beispielschemas sieht die Abfrage für die erste Seite so aus:
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 ist die Spalte für die Auflösung von Unentschieden, da ReleaseTimestamp kein Schlüssel ist. Es kann zwei verschiedene Alben mit demselben Wert für ReleaseTimestamp geben.
Um fortzufahren, führt die Anwendung dieselbe Abfrage noch einmal aus, aber mit einer WHERE-Klausel, die die Ergebnisse der vorherigen Seite einschränkt. Die zusätzliche Bedingung muss die Schlüsselrichtung (aufsteigend oder absteigend), die Spalten für die Auflösung von Unentschieden und die Reihenfolge der NULL-Werte für Spalten mit Nullwerten berücksichtigen.
In unserem Beispiel ist AlbumId die einzige Schlüsselspalte (in aufsteigender Reihenfolge) und darf nicht NULL sein. Die Bedingung lautet also:
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
In diesem Beispiel werden die Abfrageparameter $1, $2, $3 und $4 verwendet, die an die für last_page_release_timestamp, last_page_album_id, query bzw. page_size angegebenen Werte gebunden sind.
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 interpretiert diese Art von Bedingung als suchbar. Das bedeutet, dass Spanner den Index für Dokumente, die Sie herausfiltern, nicht liest. Diese Optimierung macht die schlüsselbasierte Paginierung viel effizienter als die offsetbasierte Paginierung.
Offsetbasierte Paginierung verwenden
Bei der offsetbasierten Paginierung werden die Klauseln LIMIT und OFFSET der SQL-Abfrage verwendet, um Seiten zu simulieren. Der Wert von LIMIT gibt die Anzahl der Ergebnisse pro Seite an.
Der Wert von OFFSET ist für die erste Seite auf null, für die zweite Seite auf die Seitengröße und für die dritte Seite auf das Doppelte der Seitengröße festgelegt.
Mit der folgenden Abfrage wird beispielsweise die dritte Seite mit einer Seitengröße von 50 abgerufen:
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;
Verwendungshinweise:
- Die
ORDER BYAnweisung wird dringend empfohlen, um eine konsistente Reihenfolge zwischen den Seiten zu gewährleisten. - Verwenden Sie in Produktionsabfragen Abfrageparameter anstelle von Konstanten, um
LIMITundOFFSETanzugeben, damit das Abfrage-Caching effizienter wird. Weitere Informationen finden Sie unter Abfrageparameter.
Nächste Schritte
- Informationen zum Ranking von Suchergebnissen
- Informationen zum Durchführen einer Teilstringsuche.
- Volltext- und Nicht-Text-Suchanfragen kombinieren
- Mehrere Spalten durchsuchen