Kita kini menguasai tiga mode pencarian full-text MySQL, dan di titik ini penting untuk jujur tentang pagar kayunya. Full-text search MySQL adalah fitur yang kuat namun berbatas: daftar stopword yang memotong kata tertentu, panjang kata minimum tiga karakter, perilaku khusus untuk bahasa tanpa spasi antar kata, serta index yang tumbuh besar seiring koleksi teks. Pada chapter penutup ini kita menguji tiap batasan secara nyata, menimbang biaya index terhadap manfaatnya, dan menetapkan indikator kapan beban pencarian sebaiknya dipindahkan ke mesin pencarian khusus.

Menyiapkan Tabel Latihan #

Tabel artikel sepuluh baris yang sama dipakai terakhir kali, termasuk full-text index multi kolom:

sql
DROP DATABASE IF EXISTS belajar_fts;
CREATE DATABASE belajar_fts;
USE belajar_fts;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE artikel (
  id INT AUTO_INCREMENT PRIMARY KEY,
  judul VARCHAR(100) NOT NULL,
  isi TEXT NOT NULL,
  FULLTEXT idx_ft_artikel (judul, isi)
) ENGINE=InnoDB;

INSERT INTO artikel (judul, isi) VALUES
  ('Belajar Database Relasional', 'Database relasional menyimpan data dalam tabel yang saling terhubung. MySQL adalah database relasional populer untuk aplikasi web. Indeks mempercepat pencarian data pada kolom tertentu.'),
  ('Panduan Menyeduh Espresso', 'Espresso adalah basis minuman kopi modern. Seduh espresso memakai mesin kopi bertekanan tinggi dan biji kopi gelap. Grinder yang baik menghasilkan rasa espresso seimbang.'),
  ('Memasak Rendang Daging', 'Rendang daging adalah masakan khas Padang. Memasak rendang membutuhkan santan, cabai, dan rempah. Proses memasak rendang memakan waktu beberapa jam hingga kuah mengering.'),
  ('Cloud Computing untuk Pemula', 'Cloud computing menyediakan server dan penyimpanan lewat internet. Perusahaan menyewa cloud agar tidak membeli server fisik. Layanan cloud populer contohnya penyimpanan berkas dan basis data terkelola.'),
  ('Asal Biji Kopi Gayo', 'Kopi Gayo tumbuh di dataran tinggi Aceh. Petani kopi Gayo memanen biji secara manual. Citarasa kopi Gayo khas dengan aroma rempah dan keasaman seimbang.'),
  ('Nasi Goreng Kampung', 'Nasi goreng kampung adalah masakan rumahan favorit. Bumbu nasi goreng terdiri dari bawang, cabai, dan kecap. Memasak nasi goreng butuh api besar agar wangi.'),
  ('JavaScript di Browser', 'JavaScript membuat halaman web menjadi interaktif. Browser menjalankan JavaScript pada sisi klien. Framework JavaScript mempercepat pembuatan antarmuka aplikasi modern.'),
  ('Cold Brew vs Kopi Panas', 'Cold brew diseduh dengan air dingin selama belasan jam. Rasa cold brew lebih halus dibanding kopi panas. Penikmat kopi sering menyimpan cold brew di kulkas.'),
  ('Tempe Sumber Protein', 'Tempe adalah makanan fermentasi kedelai khas Indonesia. Tempe mengandung protein tinggi dan harganya murah. Olahan tempe contohnya tempe goreng, tempe bacem, dan tempe crispy.'),
  ('Keamanan Aplikasi Web', 'Keamanan aplikasi web wajib dijaga sejak awal pengembangan. Pengembang memvalidasi input pengguna dan menyimpan sandi terenkripsi. Serangan umum pada aplikasi web contohnya SQL injection.');

OPTIMIZE TABLE artikel;

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0

+---------------------+----------+----------+-------------------------------------------------------------------+
| Table               | Op       | Msg_type | Msg_text                                                          |
+---------------------+----------+----------+-------------------------------------------------------------------+
| belajar_fts.artikel | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| belajar_fts.artikel | optimize | status   | OK                                                                |
+---------------------+----------+----------+-------------------------------------------------------------------+
2 rows in set (0.00 sec)

Stopword Bawaan #

MySQL mengabaikan sejumlah kata yang dianggap terlalu umum untuk diberi skor. Daftar stopword bawaan berisi kata-kata bahasa Inggris seperti the, of, dan and. Kita bisa membuktikan pengabaian ini langsung:

sql
SELECT id, judul
FROM artikel
WHERE MATCH (judul, isi) AGAINST ('the');

Output yang Dihasilkan:

text
Empty set (0.00 sec)

Query mengembalikan nol baris meskipun kata-kata seperti the tidak pernah muncul di koleksi kita — sebelum itu pun, kata tersebut sudah dibuang saat index dibangun. Konsekuensi praktisnya: kata yang kebetulan masuk daftar stopword tidak akan pernah bisa dicari. Kabar baiknya untuk konten Bahasa Indonesia, daftar stopword bawaan tidak memuat kata Indonesia umum seperti dan atau yang, sehingga hampir seluruh kosakata koleksi kita tetap terindeks. Daftar stopword bisa pula diganti dengan file kustom melalui variabel innodb_ft_server_stopword_table — topik lanjutan yang perlu dipertimbangkan saat koleksi dokumen berbahasa Indonesia tumbuh besar dan kata-kata lokal yang terlalu sering muncul mulai mendominasi skor.

Panjang Kata Minimum #

Full-text index InnoDB hanya mengindeks kata dengan panjang minimal tiga karakter — nilai yang dikendalikan variabel innodb_ft_min_token_size. Kita periksa nilainya dan uji dampaknya:

sql
SHOW VARIABLES LIKE 'innodb_ft_min_token_size';

Output yang Dihasilkan:

text
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_ft_min_token_size | 3     |
+--------------------------+-------+
1 row in set (0.00 sec)
sql
SELECT id, judul
FROM artikel
WHERE MATCH (judul, isi) AGAINST ('ke');

Output yang Dihasilkan:

text
Empty set (0.00 sec)

Kata ke yang hanya dua karakter tidak ditemukan apa pun karena memang tidak pernah masuk ke index. Batas ini jarang terasa pada teks Indonesia — hampir semua kata bermakna berdurasi tiga karakter atau lebih — tetapi bisa menggigit pada kode singkat, nomor versi, atau singkatan dua huruf. Mengubah variabel ini mengharuskan index dibangun ulang, sehingga keputusannya sebaiknya diambil sebelum aplikasi berjalan, bukan setelah pengguna mengeluh.

Bahasa Tanpa Spasi dan Parser Ngram #

Algoritma default full-text memecah teks berdasarkan spasi dan tanda baca — pendekatan yang gagal untuk bahasa yang menulis kata tanpa spasi, seperti bahasa Jepang, Mandarin, atau Korea. Untuk kebutuhan tersebut, InnoDB menyediakan parser ngram yang memecah teks menjadi potongan dua karakter bergerak. Membuat index dengan parser ini cukup menambahkan klausa WITH PARSER ngram:

sql
CREATE TABLE catatan_jepang (
  id INT AUTO_INCREMENT PRIMARY KEY,
  isi TEXT NOT NULL,
  FULLTEXT idx_ft_jepang (isi) WITH PARSER ngram
) ENGINE=InnoDB;

INSERT INTO catatan_jepang (isi) VALUES ('データベースの勉強を始めました');

SELECT id, isi
FROM catatan_jepang
WHERE MATCH (isi) AGAINST ('データベース' WITH QUERY EXPANSION);

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)

+----+-----------------------------------------------+
| id | isi                                           |
+----+-----------------------------------------------+
|  1 | データベースの勉強を始めました                |
+----+-----------------------------------------------+
1 row in set (0.00 sec)

Contoh di atas membuktikan parser ngram membuat pencarian teks Jepang dapat berjalan. Untuk koleksi berbahasa Indonesia, parser default sudah memadai — bahasa kita berpemisah kata yang jelas, dan pencarian dengan boolean mode serta query expansion berjalan seperti yang kita latih sepanjang section ini.

Bukan Alat Exact Match #

Full-text search dirancang untuk menilai relevansi, bukan mencocokkan teks secara persis. Ketika kebutuhannya adalah awalan pasti — misalnya mencari semua judul berawalan Kopi — operator LIKE 'Kopi%' dengan index B-tree biasa lebih tepat:

sql
SELECT id, judul
FROM artikel
WHERE judul LIKE 'Kopi%';

Output yang Dihasilkan:

text
Empty set (0.00 sec)

Perbandingan ringkas kedua pendekatan ini menjadi pegangan memilih:

KebutuhanAlat yang tepatAlasan
Awalan pasti, contoh Kopi%Index B-tree + LIKE 'awalan%'Index terpakai, hasil deterministik
Kata di tengah teks panjangFull-text searchB-tree tidak membantu %kata%
Peringkat relevansiFull-text + skorB-tree tidak punya konsep skor
Frasa persis dengan operator proximityBoolean mode "frasa"Full-text mendukung
Cek substring kode, mis. INV-2026LIKE / LOCATEToken pendek tak terindeks FTS

Kapan Beralih ke Mesin Pencarian Khusus #

Ketika tuntutan melewati kemampuan full-text MySQL, biasanya polanya konsisten: pencarian lintas tabel dengan bobot field berbeda, autocomplete per keystroke dengan latensi milidetik, stemming Bahasa Indonesia (menyeduh sama dengan seduh), fuzzy matching typo, atau faset filter kompleks. Mesin pencarian khusus seperti Elasticsearch, Meilisearch, atau Typesense memang dirancang untuk beban tersebut — dengan biaya operasi server tambahan dan sinkronisasi data yang harus dijaga. Pola yang sehat di banyak aplikasi: mulai dengan full-text MySQL yang sudah tertanam di tempat datanya hidup, ukur kepuasan pengguna dan latensi query, lalu pindahkan hanya fitur pencarian yang terbukti melampaui batas. Pemindahan sebagian juga sah: index khusus untuk pencarian publik, sementara pencarian internal admin tetap memakai MySQL.

Referensi #

Section full-text search tuntas: dari konsep index terbalik sampai batas-batas praktisnya. Perjalanan berikutnya berpindah ke sisi kecepatan — section query optimization, dimulai dengan membaca query execution plan melalui EXPLAIN.