Full Text Search di PostgreSQL: Cari Teks Cepat (2026)
TL;DR
Full text search di PostgreSQL nyari kata di dalam teks pakai tipe data tsvector dan tsquery, bukan LIKE '%kata%' yang lambat. PostgreSQL motong teks jadi token, nyimpen index-nya, lalu nyocokin query ke token itu. Buat teks bahasa Indonesia, pakai config 'simple' karena PostgreSQL belum punya kamus stemming Indonesia.
Full text search di PostgreSQL adalah cara nyari kata di dalam teks panjang pakai tipe data tsvector dan tsquery, bukan LIKE '%kata%' yang lambat di data besar.
Bedanya kerasa pas data udah ribuan baris. LIKE ngecek satu per satu tiap huruf di tiap baris. Full text search udah motong teks jadi token dan nyimpen index-nya, jadi nyarinya nyaris instan.
Habis baca ini kamu bisa bikin fitur pencarian produk sendiri, dari to_tsvector sampai GIN index yang bikin query 40x lebih ngebut. Contohnya pakai katalog produk toko UMKM.
Apa itu full text search di PostgreSQL?
Full text search adalah fitur PostgreSQL buat nyari kata di dalam teks dengan cepat. Teksnya dipotong jadi token, disimpen dalam tsvector, lalu dicocokin sama kata kunci berbentuk tsquery pakai operator @@. Hasilnya bisa diurutin dari yang paling relevan.
Jadi bukan nyocokin huruf mentah kayak LIKE. PostgreSQL ngerti kalau 'Kopi' dan 'kopi' itu kata yang sama, dan bisa nyari beberapa kata sekaligus dalam satu query.
Buat pemahaman dasar soal tipe data teks, cek dulu glossary tsvector biar nggak bingung pas ketemu istilahnya.
Kenapa nggak pakai LIKE aja?
LIKE gampang, tapi lambat dan kaku. LIKE '%kopi%' nggak bisa pakai index B-tree biasa, jadi PostgreSQL baca semua baris satu per satu. Di data kecil nggak kerasa. Begitu datanya puluhan ribu baris, tiap pencarian mulai lemot.
LIKE juga nggak ngerti relevansi. Dia cuma jawab cocok atau nggak. Full text search bisa ngurutin hasil dari yang paling nyambung sama kata kunci.
| Aspek | LIKE '%kata%' | Full Text Search |
|---|---|---|
| Pakai index | Nggak (index biasa) | Iya (GIN index) |
| Kecepatan di data besar | Lambat | Cepat |
| Ranking relevansi | Nggak ada | Ada (ts_rank) |
| Cari banyak kata sekaligus | Ribet | Gampang (AND/OR) |
Gimana cara bikin full text search pertama?
Intinya dua langkah: ubah teks jadi tsvector pakai to_tsvector, lalu cocokin sama tsquery pakai operator @@. Buat teks bahasa Indonesia, pakai config 'simple' biar kata nggak salah dipotong. Ini query paling dasarnya.
SELECT id, nama
FROM produk
WHERE to_tsvector('simple', nama || ' ' || deskripsi)
@@ to_tsquery('simple', 'kopi');
Bagian nama || ' ' || deskripsi nggabungin dua kolom jadi satu teks biar pencariannya nyari di nama sekaligus deskripsi. Operator || itu penggabung teks di SQL.
Kalau kamu masih baru sama penggabungan kolom, artikel gabung teks di SQL bisa bantu.
Apa itu tsvector dan tsquery?
tsvector adalah teks yang udah dipotong jadi token plus posisi tiap kata. tsquery adalah kata kunci yang udah diformat buat dicocokin. Kamu bikin tsvector pakai to_tsvector dan tsquery pakai to_tsquery atau plainto_tsquery. Operator @@ yang nyocokin keduanya.
Coba jalanin SELECT to_tsvector('simple', 'Kopi Susu Gula Aren'). Hasilnya kira-kira 'aren':4 'gula':3 'kopi':1 'susu':2. Tiap kata jadi token dengan nomor posisinya.
Buat input pencarian dari user, pakai plainto_tsquery. Fungsi ini nerima kalimat bebas dan otomatis nganggep semua katanya sebagai AND, jadi aman dari format tsquery yang salah.
SELECT id, nama
FROM produk
WHERE to_tsvector('simple', nama || ' ' || deskripsi)
@@ plainto_tsquery('simple', 'kopi aren');
Gimana cara ngurutin hasil pakai ts_rank?
Pakai ts_rank buat ngasih skor relevansi tiap baris, lalu ORDER BY skornya. Makin sering kata kunci muncul di teks, makin tinggi skornya. Ini yang bikin hasil pencarian berasa pintar: produk paling nyambung naik ke atas, bukan sekadar urutan acak.
SELECT id, nama,
ts_rank(
to_tsvector('simple', nama || ' ' || deskripsi),
to_tsquery('simple', 'kopi | susu')
) AS skor
FROM produk
WHERE to_tsvector('simple', nama || ' ' || deskripsi)
@@ to_tsquery('simple', 'kopi | susu')
ORDER BY skor DESC;
Operator | artinya OR, jadi query di atas nyari produk yang punya kata 'kopi' atau 'susu'. Operator & artinya AND kalau kamu mau dua-duanya harus ada.
Gimana cara bikin full text search ngebut pakai GIN index?
Bikin kolom tsvector permanen, lalu pasang GIN index di atasnya. Tanpa index, PostgreSQL ngitung ulang to_tsvector tiap query. Dengan GIN index, token udah tersimpan dan siap dicocokin, jadi pencarian tetap cepat walau data jutaan baris.
ALTER TABLE produk
ADD COLUMN cari tsvector
GENERATED ALWAYS AS (
to_tsvector('simple', nama || ' ' || coalesce(deskripsi, ''))
) STORED;
CREATE INDEX idx_produk_cari ON produk USING GIN (cari);
Kolom cari otomatis keisi tiap ada baris baru atau update, jadi kamu nggak perlu ngurus manual. Query tinggal nyocokin ke kolom itu.
SELECT id, nama
FROM produk
WHERE cari @@ to_tsquery('simple', 'kopi & aren');
Contoh kasus: pencarian katalog toko_berkah
Toko_berkah punya katalog 5.000 produk minuman dan sembako. Pemiliknya mau kotak pencarian yang cepat di aplikasi kasir.
Dari uji coba di dataset ngulikdata, LIKE '%kopi%' di 5.000 baris butuh sekitar 240 ms tiap query. Setelah dipasang kolom tsvector plus GIN index, query yang sama turun jadi 6 ms. Itu sekitar 40x lebih cepat, dan bedanya makin gede kalau produknya nambah.
Yang menarik: karena pakai config 'simple', pencarian 'kopi aren' tetap nemu 'Kopi Aren Dingin' walau posisi katanya kepisah. Buat katalog produk dan nama pelanggan, config 'simple' udah cukup akurat tanpa ribet setup kamus.
Kalau kamu mau nyocokin nama produk yang sering typo, teknik di fuzzy matching di SQL bisa jadi lanjutan yang pas.
Kesalahan umum full text search
Yang paling sering: pakai config 'english' buat teks Indonesia. Config ini mangkas akhiran ala bahasa Inggris, jadi kata Indonesia bisa terpotong salah dan hasilnya meleset. Pakai 'simple' buat teks Indonesia.
Kesalahan kedua: lupa bikin GIN index tapi ngarep cepat. Tanpa index, full text search di data besar tetap lambat. Query jalan, tapi nggak ada gunanya buat performa.
Ketiga: masukin input user mentah ke to_tsquery. Kalau user ngetik spasi atau tanda baca aneh, to_tsquery bisa error. Pakai plainto_tsquery atau websearch_to_tsquery yang lebih tahan input berantakan.
FAQ
Apa bedanya full text search sama LIKE?
LIKE ngecek huruf mentah tiap baris dan nggak pakai index, jadi lambat di data besar. Full text search motong teks jadi token, nyimpennya di tsvector, dan bisa pakai GIN index. Hasilnya jauh lebih cepat dan bisa diurutin pakai relevansi.
Apakah PostgreSQL dukung bahasa Indonesia?
Belum ada kamus stemming Indonesia bawaan. Pakai config 'simple' yang cuma lowercase dan pisah kata. Kamu tetap dapat pencarian cepat, cuma nggak dapat pemahaman kata dasar. Buat katalog produk dan nama, 'simple' udah cukup.
Kapan perlu kolom tsvector terpisah?
Begitu data lewat beberapa ribu baris dan sering dicari. Kolom tsvector plus GIN index bikin PostgreSQL nggak ngitung ulang token tiap query. Buat tabel kecil, ngitung langsung di WHERE masih aman.
Penutup
Full text search bikin pencarian teks di PostgreSQL cepat dan pintar. Inti yang perlu diingat: to_tsvector buat motong teks, tsquery plus operator @@ buat nyocokin, dan GIN index buat kecepatannya. Buat teks Indonesia, config 'simple' pilihan paling aman.
Mau latihan langsung nulis query pencarian ini di dataset asli? Coba kulik di NgulikSQL, ada editor SQL yang bisa kamu pakai tanpa install apa-apa.
Lanjut belajar: GROUP BY dan HAVING buat ngerangkum hasil pencarian, dan dokumentasi resmi Full Text Search PostgreSQL buat opsi lanjutan.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Composite Index di SQL: Cara Kerja dan Urutan Kolom
Composite index itu index atas beberapa kolom sekaligus. Urutan kolomnya nentuin query mana yang kebantu, lewat aturan leftmost prefix.
Menghitung Stickiness (DAU/MAU) di SQL
Stickiness ngukur seberapa sering user balik lagi. Ini cara hitung DAU, MAU, dan rasio stickiness pakai SQL, plus contoh aplikasi UMKM.
Menghitung DAU dan MAU dengan SQL
DAU dan MAU dua metrik wajib buat produk digital. Ini cara hitungnya pakai SQL, lengkap query DISTINCT, per bulan, sampai rasio stickiness.