Memberi nomor halaman pada hasil penelusuran

Aplikasi web sering memaginasi data saat disajikan kepada pengguna. Pengguna akhir menerima satu halaman hasil, dan saat mereka membuka halaman berikutnya, kumpulan hasil berikutnya akan diambil dan ditampilkan. Halaman ini menjelaskan cara menambahkan penomoran halaman ke hasil penelusuran saat melakukan penelusuran teks lengkap di Spanner.

Opsi penomoran halaman

Ada dua cara untuk menerapkan kueri yang dipaginasi di Spanner: penomoran halaman berbasis kunci (direkomendasikan) dan penomoran halaman berbasis offset.

Penomoran halaman berbasis kunci adalah metode untuk mengambil hasil penelusuran dalam potongan yang lebih kecil dan lebih mudah dikelola sekaligus memastikan hasil yang konsisten di seluruh permintaan. ID unik (yaitu "kunci") dari hasil terakhir suatu halaman digunakan sebagai titik referensi untuk mengambil kumpulan hasil berikutnya.

Spanner umumnya merekomendasikan penggunaan penomoran halaman berbasis kunci. Meskipun penomoran halaman berbasis offset lebih mudah diterapkan, ada dua kelemahan signifikan:

  1. Biaya kueri yang lebih tinggi:Penomoran halaman berbasis offset berulang kali mengambil dan menghapus hasil yang sama, sehingga meningkatkan biaya dan menurunkan performa.
  2. Hasil yang Tidak Konsisten: Dalam kueri dengan penomoran halaman, setiap halaman biasanya diambil pada stempel waktu baca yang berbeda. Misalnya, halaman pertama mungkin berasal dari kueri pada pukul 13.00, dan halaman berikutnya dari kueri pada pukul 13.10. Artinya, hasil penelusuran dapat berubah di antara kueri, sehingga menghasilkan hasil yang tidak konsisten di seluruh halaman.

Sebaliknya, penomoran halaman berbasis kunci menggunakan ID unik (kunci) dari hasil terakhir halaman untuk mengambil kumpulan hasil berikutnya. Hal ini memastikan pengambilan yang efisien dan hasil yang konsisten, meskipun data dasarnya berubah.

Untuk memberikan stabilitas dalam hasil halaman, aplikasi dapat mengeluarkan semua kueri untuk halaman yang berbeda pada stempel waktu yang sama. Namun, hal ini dapat gagal jika kueri melebihi periode retensi versi (defaultnya adalah 1 jam). Misalnya, kegagalan ini terjadi jika version_gc adalah satu jam, dan pengguna akhir mengambil hasil pertama pada pukul 13.00 dan mengklik Berikutnya pada pukul 15.00.

Menggunakan penomoran halaman berbasis kunci

Penomoran halaman berbasis kunci mengingat item terakhir halaman sebelumnya dan menggunakannya sebagai titik awal untuk kueri halaman berikutnya. Untuk melakukannya, kueri harus menampilkan kolom yang ditentukan dalam klausa ORDER BY dan membatasi jumlah baris menggunakan LIMIT.

Agar penomoran halaman berbasis kunci berfungsi, kueri harus mengurutkan hasil berdasarkan urutan total yang ketat. Cara termudah untuk mendapatkannya adalah dengan memilih total pesanan, lalu menambahkan kolom pemecah seri, jika diperlukan. Dalam sebagian besar kasus, urutan total adalah urutan pengurutan indeks penelusuran dan kombinasi kolom unik adalah kunci utama tabel dasar.

Dengan skema contoh Albums, untuk halaman pertama, kuerinya akan terlihat seperti berikut:

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 adalah penentu karena ReleaseTimestamp bukan kunci. Mungkin ada dua album berbeda dengan nilai yang sama untuk ReleaseTimestamp.

Untuk melanjutkan, aplikasi menjalankan kueri yang sama lagi, tetapi dengan klausa WHERE yang membatasi hasil dari halaman sebelumnya. Kondisi tambahan harus memperhitungkan arah utama (menaik versus menurun), pemecah seri, dan urutan nilai NULL untuk kolom nullable.

Dalam contoh ini, AlbumId adalah satu-satunya kolom kunci (dalam urutan menaik) dan tidak boleh NULL, sehingga kondisinya adalah sebagai berikut:

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

Contoh ini menggunakan parameter kueri $1, $2, $3, dan $4 yang terikat ke nilai yang ditentukan untuk last_page_release_timestamp, last_page_album_id, query, dan 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 menafsirkan jenis kondisi ini sebagai dapat dicari. Artinya, Spanner tidak membaca indeks untuk dokumen yang Anda kecualikan. Pengoptimalan ini membuat penomoran halaman berbasis kunci jauh lebih efisien daripada penomoran halaman berbasis offset.

Menggunakan penomoran halaman berbasis offset

Penomoran berbasis offset memanfaatkan klausa LIMIT dan OFFSET dari kueri SQL untuk menyimulasikan halaman. Nilai LIMIT menunjukkan jumlah hasil per halaman. Nilai OFFSET ditetapkan ke nol untuk halaman pertama, ukuran halaman untuk halaman kedua, dan dua kali ukuran halaman untuk halaman ketiga.

Misalnya, kueri berikut mengambil halaman ketiga, dengan ukuran halaman 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;

Catatan Penggunaan:

  • Klausul ORDER BY sangat direkomendasikan untuk memastikan pengurutan yang konsisten antar-halaman.
  • Dalam kueri produksi, gunakan parameter kueri, bukan konstanta, untuk menentukan LIMIT dan OFFSET agar membuat caching kueri lebih efisien. Untuk mengetahui informasi selengkapnya, lihat Parameter kueri.

Langkah berikutnya