Pencarian Teks Penuh FTS5

Tabel virtual FTS5, query MATCH, dan peringkat hasil pencarian.

Daftar isi

Pencarian teks penuh (full-text search) adalah pencarian atas isi kolom teks dengan cepat dan urutan relevansi, dan SQLite menyediakannya melalui FTS5, yaitu ekstensi yang sudah menyatu pada sqlite3 CLI yang dipakai di jalur ini. Topik ini membahas pembuatan tabel virtual FTS5 untuk koleksi buku, query MATCH dengan istilah, prefiks, frasa, dan gabungan istilah, peringkat hasil dengan rank serta bm25(), penyajian potongan teks dengan snippet() dan highlight(), hingga perbandingan FTS5 dengan LIKE. Seluruh keluaran diperoleh dari eksekusi nyata pada tabel kecil sehingga dapat direproduksi ulang satu per satu.

Tabel virtual FTS5#

CREATE VIRTUAL TABLE dengan modul fts5 membuat sebuah virtual table, yaitu tabel yang datanya dikelola oleh modul khusus dan bukan oleh mesin penyimpanan biasa. Kolom teks yang dideklarasikan pada definisinya diurai menjadi token, dan setiap token dipetakan ke daftar baris yang memuatnya dalam struktur yang disebut inverted index. Pemetaan inilah yang membuat pencarian kata tidak perlu membaca seluruh isi tabel. Blok berikut membuat katalog pencarian untuk tiga buku, lalu mencari kata algoritma dengan operator MATCH.

sql Tabel virtual FTS5 dan pencocokan MATCH
CREATE VIRTUAL TABLE buku_fts USING fts5(judul, deskripsi);
INSERT INTO buku_fts (rowid, judul, deskripsi) VALUES
  (1, 'Dasar Algoritma', 'Buku pengantar algoritma dan struktur data untuk pemula'),
  (2, 'Peta Langit', 'Panduan mengenal rasi bintang dan objek langit malam'),
  (3, 'Algoritma Terapan', 'Penerapan algoritma pada masalah pencarian dan pengurutan data');

SELECT judul FROM buku_fts WHERE buku_fts MATCH 'algoritma';
text Keluaran
Dasar Algoritma
Algoritma Terapan

Kedua judul muncul karena kata algoritma terdapat pada kolomnya, dan urutannya mengikuti rowid karena belum ada peringkat yang diminta. Pencarian dilakukan terhadap token yang tersimpan, sehingga bentuk kata diperlakukan sebagai satu kesatuan dan tidak dipecah menjadi akar kata. Baris masuk dan keluar dari indeks bersama pernyataan INSERT dan DELETE biasa, sehingga tabel FTS5 dirawat sebagaimana tabel lain tanpa langkah pengindeksan ulang manual. Tabel virtual ini juga menyediakan kolom semu bernama rank yang hanya bermakna dalam konteks MATCH, sebagaimana dipakai pada bagian peringkat.

Query MATCH: prefiks, frasa, dan gabungan istilah#

Kata kunci MATCH menerima sintaks kueri milik FTS5 yang jauh lebih kaya daripada perbandingan biasa. Tanda bintang di akhir istilah membentuk pencarian prefiks yang mencocokkan seluruh token berawalan tersebut, pasangan tanda kutip membentuk frasa yang tokennya harus berurutan, sedangkan operator AND, OR, dan NOT menggabungkan istilah. Blok berikut menjalankan ketiga bentuk yang paling sering dipakai pada tabel yang sama. Blok berikut menjalankan ketiga bentuk itu pada tabel yang sama dan menampilkan keluarannya berdampingan.

sql Prefiks, frasa, dan gabungan istilah pada MATCH
CREATE VIRTUAL TABLE buku_fts USING fts5(judul, deskripsi);
INSERT INTO buku_fts (rowid, judul, deskripsi) VALUES
  (1, 'Dasar Algoritma', 'Buku pengantar algoritma dan struktur data untuk pemula'),
  (2, 'Peta Langit', 'Panduan mengenal rasi bintang dan objek langit malam'),
  (3, 'Algoritma Terapan', 'Penerapan algoritma pada masalah pencarian dan pengurutan data');

SELECT judul FROM buku_fts WHERE buku_fts MATCH 'algo*';
SELECT judul FROM buku_fts WHERE buku_fts MATCH '"struktur data"';
SELECT judul FROM buku_fts WHERE buku_fts MATCH 'algoritma OR langit';
text Keluaran
Dasar Algoritma
Algoritma Terapan
Dasar Algoritma
Dasar Algoritma
Peta Langit
Algoritma Terapan

Tiga query pada blok itu menghasilkan tiga kelompok baris yang tersambung tanpa pemisah. Kelompok pertama adalah hasil prefiks algo* yang mencakup dua token berbeda, yaitu algoritma dan Algoritma pada judulnya. Kelompok kedua hanya satu baris karena frasa “struktur data” harus muncul berurutan pada satu kolom. Kelompok ketiga menggabungkan dua istilah dengan OR sehingga baris yang memuat salah satunya ikut tampil, sedangkan pemisahan istilah dengan spasi bermakna AND yang menuntut keduanya. Operator NOT melengkapi gabungan itu, misalnya algoritma NOT langit yang membuang baris yang memuat istilah kedua.

Peringkat dengan rank dan bm25()#

FTS5 memberi setiap baris hasil MATCH sebuah skor relevansi melalui fungsi bm25(), yaitu implementasi skema penilaian BM25 yang menghitung kecocokan berdasarkan frekuensi istilah dan panjang dokumen. Skornya bernilai negatif, dan nilai yang lebih rendah atau lebih negatif berarti lebih relevan. Nama rank berfungsi sebagai alias untuk bm25(), sehingga ORDER BY rank sudah cukup untuk mengurutkan hasil dari yang paling cocok. Blok berikut menampilkan kedua kolom itu sekaligus.

sql Skor bm25 dan pengurutan dengan rank
CREATE VIRTUAL TABLE buku_fts USING fts5(judul, deskripsi);
INSERT INTO buku_fts (rowid, judul, deskripsi) VALUES
  (1, 'Dasar Algoritma', 'Buku pengantar algoritma dan struktur data untuk pemula'),
  (2, 'Peta Langit', 'Panduan mengenal rasi bintang dan objek langit malam'),
  (3, 'Algoritma Terapan', 'Penerapan algoritma pada masalah pencarian dan pengurutan');

SELECT judul, rank, bm25(buku_fts) FROM buku_fts
WHERE buku_fts MATCH 'algoritma' ORDER BY rank;
text Keluaran
Algoritma Terapan|-1.4021978021978021e-06|-1.4021978021978021e-06
Dasar Algoritma|-1.3617929562433296e-06|-1.3617929562433296e-06

Kedua kolom skor memang berisi angka yang sama persis karena rank hanyalah nama lain bagi bm25(). Algoritma Terapan menempati posisi teratas dengan skor yang lebih negatif, dan posisi itu dipengaruhi oleh panjang deskripsinya yang lebih pendek relatif terhadap frekuensi istilah. Angka absolutnya kecil pada koleksi tiga baris ini, sehingga yang perlu dibaca adalah urutannya, dan laporan nyata cukup memakai ORDER BY rank tanpa menampilkan skornya kepada pengguna. Skor ini juga memungkinkan penggabungan hasil dari sumber berbeda karena angkanya dapat dibandingkan satu sama lain.

Potongan teks dengan snippet dan highlight#

Daftar hasil pencarian menjadi lebih mudah dinilai apabila pengguna melihat potongan teks yang memuat kecocokannya. Fungsi snippet() mengembalikan jendela teks pendek di sekitar kecocokan terbaik, sedangkan highlight() mengembalikan nilai kolom utuh dengan penanda di setiap istilah yang cocok. Keduanya hanya sah dipanggil pada query yang memakai MATCH. Keduanya menerima nama tabel FTS5, indeks kolom, serta teks pembuka dan penutup untuk penanda itu.

sql snippet dan highlight pada hasil pencarian
CREATE VIRTUAL TABLE buku_fts USING fts5(judul, deskripsi);
INSERT INTO buku_fts (rowid, judul, deskripsi) VALUES
  (1, 'Dasar Algoritma', 'Buku pengantar algoritma dan struktur data. Setiap bab membahas satu algoritma beserta contohnya'),
  (2, 'Peta Langit', 'Panduan mengenal rasi bintang dan objek langit malam untuk pemula'),
  (3, 'Algoritma Terapan', 'Penerapan algoritma pada masalah pencarian dan pengurutan data');

SELECT snippet(buku_fts, 1, '[', ']', '...', 6) FROM buku_fts WHERE buku_fts MATCH 'algoritma';
SELECT highlight(buku_fts, 0, '<b>', '</b>') FROM buku_fts WHERE buku_fts MATCH 'algoritma';
text Keluaran
Buku pengantar [algoritma] dan struktur data...
Penerapan [algoritma] pada masalah pencarian dan...
Dasar <b>Algoritma</b>
<b>Algoritma</b> Terapan

Argumen 1 pada snippet() menyatakan kolom deskripsi, sementara argumen 0 pada highlight() menyatakan kolom judul, dan urutan ini mengikuti urutan deklarasi pada CREATE VIRTUAL TABLE. snippet() menandai kecocokan dengan kurung siku lalu memotong sisanya dengan elipsis karena jendelanya dibatasi enam token. Argumen terakhirnya adalah banyaknya token yang ditampilkan, sehingga panjang potongan dapat dikendalikan sesuai ruang tampilan antarmuka. Judul yang pendek tidak terpotong oleh highlight(), sehingga keduanya dipakai berpasangan, yaitu judul ditandai utuh dan deskripsi dipotong di sekitar kecocokannya. Penandanya bebas ditentukan, misalnya elemen <mark> pada aplikasi web agar kecocokan tampil dengan sorotan warna.

FTS5 dibandingkan LIKE#

LIKE mencocokkan pola dengan memindai isi setiap baris satu per satu, sehingga biayanya tumbuh seiring panjang tabel dan pencariannya memeriksa potongan teks apa pun di tengah kata. FTS5 memindai indeks terbalik yang telah menyimpan peta token ke baris, sehingga pencariannya tetap cepat pada tabel besar, tetapi kecocokannya berlaku antar token utuh dan bukan potongan kata. Blok berikut menjalankan kedua mekanisme pada data yang sama untuk memperlihatkan perbedaannya.

sql LIKE menemukan potongan kata, MATCH tidak
CREATE TABLE buku_biasa (id INTEGER PRIMARY KEY, judul TEXT, deskripsi TEXT);
INSERT INTO buku_biasa VALUES
  (1, 'Dasar Algoritma', 'Buku pengantar algoritma dan struktur data'),
  (2, 'Peta Langit', 'Panduan mengenal rasi bintang'),
  (3, 'Logika Pemrograman', 'Pendekatan algoritmik untuk pemecahan masalah');
CREATE VIRTUAL TABLE buku_fts USING fts5(judul, deskripsi);
INSERT INTO buku_fts (rowid, judul, deskripsi)
  SELECT id, judul, deskripsi FROM buku_biasa;

SELECT '---LIKE---';
SELECT judul FROM buku_biasa WHERE deskripsi LIKE '%algo%';
SELECT '---MATCH token utuh---';
SELECT judul FROM buku_fts WHERE buku_fts MATCH 'algo';
SELECT '---MATCH huruf besar---';
SELECT judul FROM buku_fts WHERE buku_fts MATCH 'ALGORITMA';
text Keluaran
---LIKE---
Dasar Algoritma
Logika Pemrograman
---MATCH token utuh---
---MATCH huruf besar---
Dasar Algoritma

LIKE menemukan dua baris karena pola %algo% mencocokkan potongan kata, termasuk algoritmik pada baris ketiga, sedangkan MATCH tanpa prefiks menghasilkan keluaran kosong karena tidak ada token yang persis bernama algo. Query MATCH terakhir membuktikan pencarian yang tidak peka huruf besar dan kecil, sebab istilah yang ditulis huruf kapital tetap menemukan baris yang sama. Ketidakpekaan ini berasal dari tokenizer bawaan bernama unicode61 yang memecah teks pada batas nonalfanumerik, melipat huruf, dan menghapus tanda diakritik. Bentuk lain yang tersedia adalah tabel dengan opsi content= yang menyebut tabel aslinya sehingga indeks hanya menyimpan token dan isi teks dibaca ulang dari tabel sumber, sebuah penghematan yang disebut external content dan menuntut sinkronisasi lewat trigger.

Ringkasan#

  • CREATE VIRTUAL TABLE dengan modul fts5 membuat tabel virtual yang teksnya diurai menjadi token dan dipetakan dalam indeks terbalik.
  • MATCH mencocokkan token utuh, prefiks dengan tanda bintang, frasa dalam tanda kutip, serta gabungan istilah dengan AND, OR, dan NOT.
  • rank adalah alias bm25() yang bernilai negatif dengan hasil paling relevan di urutan teratas, dan snippet() bersama highlight() menandai kecocokan pada teksnya.
  • LIKE memindai setiap baris dan mencocokkan potongan kata, sedangkan FTS5 mencari pada indeks token, tidak peka huruf besar kecil, dan bertahan cepat pada tabel besar.

Referensi#

  • FTS5 — SQLite — Dokumentasi lengkap FTS5, dari CREATE VIRTUAL TABLE, sintaks MATCH, bm25(), hingga snippet dan highlight.
  • SQLite Query Language — SQLite — Indeks pernyataan SQL SQLite yang memuat CREATE VIRTUAL TABLE yang mendasari tabel FTS5.